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

Unified 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: Windows, what's your problem with scoped_ptr? Created 8 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 175926a0d0dd79c8cb2013664dfacc0c002da574..49033b750de2c2373e1bc9a81fc0f00e36d564dc 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -8,11 +8,13 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/content_settings/cookie_settings.h"
#include "chrome/browser/extensions/api/web_request/web_request_api.h"
@@ -37,6 +39,7 @@
namespace helpers = extension_web_request_api_helpers;
namespace keys = extension_web_request_api_constants;
+using chrome::VersionInfo;
using helpers::CalculateOnAuthRequiredDelta;
using helpers::CalculateOnBeforeRequestDelta;
using helpers::CalculateOnBeforeSendHeadersDelta;
@@ -73,6 +76,72 @@ bool Contains(const Collection& collection, const Key& key) {
collection.end();
}
+// Parses |json_string| as a Value. Returns NULL on failure. The caller owns
+// the returned object.
+const Value* GetValueFromJson(const base::StringPiece& json_string) {
+ const Value* parsed = base::JSONReader::Read(json_string);
+ return parsed;
+}
+
+// Parses |json_string| as a DictionaryValue. Returns NULL on failure.
+scoped_ptr<const DictionaryValue> GetDictionaryFromJson(
+ const base::StringPiece& json_string) {
+ const Value* value = GetValueFromJson(json_string);
+ if (value == NULL)
+ return scoped_ptr<const DictionaryValue>();
+ // Now we own the object pointed to by |value|.
+ const DictionaryValue* dictionary_raw = NULL;
+ const bool success = value->GetAsDictionary(&dictionary_raw);
+ scoped_ptr<const DictionaryValue> dictionary(dictionary_raw);
+ if (success)
+ return dictionary.Pass();
+ else
+ return scoped_ptr<const DictionaryValue>();
+}
+
+// Parses the JSON data attached to the |message| and tries to return it.
+// Returns NULL on failure.
+scoped_ptr<const DictionaryValue> GetPartOfMessageArguments(
+ IPC::Message* message) {
+ bool success = true;
+ EXPECT_TRUE(success = (message->type() == ExtensionMsg_MessageInvoke::ID));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
Matt Perry 2012/08/02 10:11:03 Sadly this makes the code a bit hard to read. What
vabr (Chromium) 2012/08/05 18:54:46 Good idea. I actually changed the signature of Get
+ ExtensionMsg_MessageInvoke::Param param;
+ Value* temp_value = NULL;
+ EXPECT_TRUE(success = (ExtensionMsg_MessageInvoke::Read(message, &param)));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ EXPECT_TRUE(success = (param.c.GetSize() >= 2));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ EXPECT_TRUE(success = (param.c.Get(1, &temp_value)));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ std::string args;
+ EXPECT_TRUE(success = (temp_value->GetAsString(&args)));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ const Value* value = GetValueFromJson(args);
+ EXPECT_TRUE(success = (value != NULL));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ const ListValue* list = NULL;
+ EXPECT_TRUE(success = (value->GetAsList(&list)));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ scoped_ptr<const ListValue> list_scoped(list);
+ EXPECT_TRUE(success = (list->GetSize() == 1));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ // TODO(vabr): Add const once ListValue getters get corrected.
+ DictionaryValue* dictionary = NULL;
+ EXPECT_TRUE(success = (list->GetDictionary(0, &dictionary)));
+ if (!success)
+ return scoped_ptr<const DictionaryValue>();
+ return scoped_ptr<const DictionaryValue>(dictionary->DeepCopy());
+}
+
} // namespace
// A mock event router that responds to events with a pre-arranged queue of
@@ -134,6 +203,11 @@ class ExtensionWebRequestTest : public testing::Test {
context_->Init();
}
+ // Fires a URLRequest with the specified |content_type|. Method will be "POST"
+ // and the data will be |bytes|.
+ void FireURLRequestWithPostData(const char* content_type,
+ const char* bytes, size_t bytes_length);
+
MessageLoopForIO message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread io_thread_;
@@ -399,7 +473,169 @@ TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) {
ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
&profile_, extension_id, kEventName + "/1");
ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
- &profile_, extension_id, kEventName2 + "/1");
+ &profile_, extension_id, kEventName2 + "/1");
+}
+
+namespace {
+
+// Based on the string with extraInfoSpec |values|, create the numerical
+// representation. Returns true on success, otherwise false.
+bool GenerateInfoSpec(const std::string& values, int* result) {
+ // Create a ListValue of strings.
+ std::vector<std::string> split_values;
+ scoped_ptr<base::ListValue> list_value(new base::ListValue());
+ size_t num_values = Tokenize(values, ",", &split_values);
+ for (size_t i = 0; i < num_values ; ++i)
+ list_value->Append(new base::StringValue(split_values[i]));
+ return ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
+ *list_value, result);
+}
+
+} // namespace
+
+void ExtensionWebRequestTest::FireURLRequestWithPostData(
+ const char* content_type,
+ const char* bytes, size_t bytes_length) {
+ // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
+ GURL request_url("http://www.example.com");
+ net::URLRequest request(request_url, &delegate_, context_.get());
+ request.set_method("POST");
+ request.SetExtraRequestHeaderByName(
+ net::HttpRequestHeaders::kContentType, content_type, true);
+ request.AppendBytesToUpload(bytes, bytes_length);
+ ipc_sender_.PushTask(base::Bind(&base::DoNothing));
+ request.Start();
+}
+
+TEST_F(ExtensionWebRequestTest, AccessPostData) {
+ // We verify that POST data are accessible to OnBeforeRequest listeners.
+ // Three testing steps are repeated twice:
+ // 1. Register an extension requesting ExtraInfoSpec::POST_DATA and file a
+ // URLRequest with a multipart-encoded form. See it getting parsed.
+ // 2. Do the same, but without requesting ExtraInfoSpec::POST_DATA. Nothing
+ // should be parsed.
+ // 3. With ExtraInfoSpec::POST_DATA, fire a URLRequest with a chunked
+ // upload. Get the error message.
+ // Each of these steps is done once as if the channel was DEV or CANARY,
+ // and once as if it was BETA or STABLE. It is checked that POST data access
+ // is not available on BETA/STABLE, but that it works on DEV/CANARY.
+#define kBoundary "THIS_IS_A_BOUNDARY"
+#define kBlock "--" kBoundary "\r\n" \
+ "Content-Disposition: form-data; name=\"text\"\r\n" \
+ "\r\n" \
+ "test text\r\n" \
+ "--" kBoundary "--"
+ // POST data input.
+ const char kMultipartBytes[] = kBlock;
+ // Expected POST data output.
+ const std::string kPostDataPath(keys::kPostDataKey);
+ const std::string kFormDataPath(kPostDataPath + "." + keys::kPostDataFormKey);
+ const std::string kErrorPath(kPostDataPath + "." + keys::kPostDataErrorKey);
+ const std::string* kPath[] = {&kFormDataPath, &kPostDataPath, &kErrorPath};
+ // form
+ const char kFormDataString[] = "{\"text\":[\"test text\"]}";
+ scoped_ptr<const DictionaryValue> form_data(
+ GetDictionaryFromJson(kFormDataString));
+ ASSERT_TRUE(form_data.get() != NULL);
+ // error
+ const StringValue error("chunked_encoding");
+ // Summary.
+ const Value* kExpected[] = {form_data.get(), NULL, &error, NULL, NULL, NULL};
+ // Header.
+ const char kMultipart[] = "multipart/form-data; boundary=" kBoundary;
+#undef kBlock
+#undef kBoundary
+
+ // Set up a dummy extension name.
+ ExtensionWebRequestEventRouter::RequestFilter filter;
+ std::string extension_id("1");
+ const std::string string_spec_post("blocking,postData");
+ const std::string string_spec_no_post("blocking");
+ int extra_info_spec_no_post = 0;
+ int extra_info_spec_post = 0;
+
+ for (int pass = 0; pass < 2; ++pass) {
+ SetChannelForTestingWebRequest(
+ pass > 0 ? VersionInfo::CHANNEL_BETA : VersionInfo::CHANNEL_CANARY);
+
+ // Part 1.
+ // Subscribe to OnBeforeRequest with POST data requirement.
+ ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_post));
+ const std::string kEventName(keys::kOnBeforeRequest);
+ base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
+ ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
+ &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
+ filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
+
+ FireURLRequestWithPostData(
+ kMultipart, kMultipartBytes, strlen(kMultipartBytes));
+
+ MessageLoop::current()->RunAllPending();
+
+ SetChannelForTestingWebRequest(
+ pass > 0 ? VersionInfo::CHANNEL_STABLE : VersionInfo::CHANNEL_DEV);
+
+ // Part 2.
+ // Now remove the requirement of POST data.
+ ASSERT_TRUE(
+ GenerateInfoSpec(string_spec_no_post, &extra_info_spec_no_post));
+ ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
+ &profile_, extension_id, kEventName + "/1");
+ ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
+ &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
+ filter, extra_info_spec_no_post, ipc_sender_factory.GetWeakPtr());
+
+ FireURLRequestWithPostData(
+ kMultipart, kMultipartBytes, strlen(kMultipartBytes));
+
+ // Part 3.
+ // Get back the requirement of POST data.
+ ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_post));
+ ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
+ &profile_, extension_id, kEventName + "/1");
+ ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
+ &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
+ filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
+ {
+ GURL request_url("http://www.example.com");
+ net::URLRequest request(request_url, &delegate_, context_.get());
+ request.set_method("POST");
+ request.EnableChunkedUpload();
+ const char kDummyBytes[] = "dummy";
+ request.AppendChunkToUpload(kDummyBytes, strlen(kDummyBytes), true);
+ net::HttpRequestHeaders headers(request.extra_request_headers());
+ headers.SetHeader(net::HttpRequestHeaders::kTransferEncoding, "chunked");
+ request.SetExtraRequestHeaders(headers);
+ ipc_sender_.PushTask(base::Bind(&base::DoNothing));
+ request.Start();
+ }
+
+ MessageLoop::current()->RunAllPending();
+
+ // Clean-up.
+ ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
+ &profile_, extension_id, kEventName + "/1");
+ }
+
+ ResetChannelForTestingWebRequest();
+
+ IPC::Message* message = NULL;
+ TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin();
+ for (size_t test = 0; test < arraysize(kExpected); ++test) {
+ EXPECT_NE(i, ipc_sender_.sent_end());
+ message = (i++)->get();
+ scoped_ptr<const DictionaryValue>
+ details(GetPartOfMessageArguments(message).Pass());
+ ASSERT_TRUE(details.get() != NULL);
+ const Value* result = NULL;
+ EXPECT_EQ(
+ kExpected[test] != NULL, details->Get(*(kPath[test % 3]), &result));
+ if (kExpected[test] != NULL) {
+ EXPECT_TRUE(kExpected[test]->Equals(result));
+ }
+ }
+
+ EXPECT_EQ(i, ipc_sender_.sent_end());
}
struct HeaderModificationTest_Header {
@@ -629,16 +865,8 @@ namespace {
void TestInitFromValue(const std::string& values, bool expected_return_code,
int expected_extra_info_spec) {
- // Create a ListValue of strings.
- std::vector<std::string> split_values;
- scoped_ptr<base::ListValue> list_value(new base::ListValue());
- size_t num_values = Tokenize(values, ",", &split_values);
- for (size_t i = 0; i < num_values ; ++i)
- list_value->Append(new base::StringValue(split_values[i]));
int actual_info_spec;
- bool actual_return_code =
- ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
- *list_value, &actual_info_spec);
+ bool actual_return_code = GenerateInfoSpec(values, &actual_info_spec);
EXPECT_EQ(expected_return_code, actual_return_code);
if (expected_return_code)
EXPECT_EQ(expected_extra_info_spec, actual_info_spec);
@@ -665,6 +893,17 @@ TEST_F(ExtensionWebRequestTest, InitFromValue) {
"asyncBlocking",
true,
ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING);
+ SetChannelForTestingWebRequest(VersionInfo::CHANNEL_BETA);
+ TestInitFromValue(
+ "postData",
+ true,
+ 0);
+ SetChannelForTestingWebRequest(VersionInfo::CHANNEL_DEV);
+ TestInitFromValue(
+ "postData",
+ true,
+ ExtensionWebRequestEventRouter::ExtraInfoSpec::POST_DATA);
+ ResetChannelForTestingWebRequest();
// Multiple valid values are bitwise-or'ed.
TestInitFromValue(
@@ -1488,4 +1727,3 @@ TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) {
EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
EXPECT_EQ(3u, capturing_net_log.GetSize());
}
-

Powered by Google App Engine
This is Rietveld 408576698