| OLD | NEW |
| (Empty) |
| 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 "base/bind.h" | |
| 6 #include "base/message_loop.h" | |
| 7 #include "base/utf_string_conversions.h" | |
| 8 #include "content/browser/utility_process_host_impl.h" | |
| 9 #include "content/public/browser/utility_process_host_client.h" | |
| 10 #include "content/common/indexed_db/indexed_db_key.h" | |
| 11 #include "content/common/indexed_db/indexed_db_key_path.h" | |
| 12 #include "content/common/utility_messages.h" | |
| 13 #include "content/common/webkitplatformsupport_impl.h" | |
| 14 #include "content/public/common/serialized_script_value.h" | |
| 15 #include "content/public/test/test_utils.h" | |
| 16 #include "content/test/content_browser_test.h" | |
| 17 #include "googleurl/src/gurl.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerialize
dScriptValue.h" | |
| 21 #include "webkit/glue/idb_bindings.h" | |
| 22 #include "webkit/glue/web_io_operators.h" | |
| 23 | |
| 24 using WebKit::WebSerializedScriptValue; | |
| 25 using WebKit::WebIDBKeyPath; | |
| 26 | |
| 27 namespace content { | |
| 28 | |
| 29 // Enables calling WebKit::shutdown no matter where a "return" happens. | |
| 30 class ScopedShutdownWebKit { | |
| 31 public: | |
| 32 ScopedShutdownWebKit() { | |
| 33 } | |
| 34 | |
| 35 ~ScopedShutdownWebKit() { | |
| 36 WebKit::shutdown(); | |
| 37 } | |
| 38 | |
| 39 private: | |
| 40 DISALLOW_COPY_AND_ASSIGN(ScopedShutdownWebKit); | |
| 41 }; | |
| 42 | |
| 43 // Sanity test, check the function call directly outside the sandbox. | |
| 44 TEST(IDBKeyPathWithoutSandbox, Value) { | |
| 45 WebKitPlatformSupportImpl webkit_platform_support; | |
| 46 WebKit::initialize(&webkit_platform_support); | |
| 47 ScopedShutdownWebKit shutdown_webkit; | |
| 48 | |
| 49 // {foo: "zoo"} | |
| 50 char16 data_foo_zoo[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
| 51 std::vector<WebSerializedScriptValue> serialized_values; | |
| 52 serialized_values.push_back( | |
| 53 WebSerializedScriptValue::fromString(string16(data_foo_zoo, | |
| 54 arraysize(data_foo_zoo)))); | |
| 55 | |
| 56 // {foo: null} | |
| 57 char16 data_foo_null[] = {0x0353, 0x6f66, 0x306f, 0x017b}; | |
| 58 serialized_values.push_back(SerializedScriptValue( | |
| 59 false, false, string16(data_foo_null, arraysize(data_foo_null)))); | |
| 60 | |
| 61 // {} | |
| 62 char16 data_object[] = {0x017b}; | |
| 63 serialized_values.push_back(SerializedScriptValue( | |
| 64 false, false, string16(data_object, arraysize(data_object)))); | |
| 65 | |
| 66 // null | |
| 67 serialized_values.push_back( | |
| 68 WebSerializedScriptValue::fromString(string16())); | |
| 69 | |
| 70 std::vector<WebKit::WebIDBKey> values; | |
| 71 IndexedDBKeyPath key_path; | |
| 72 | |
| 73 key_path.SetString(UTF8ToUTF16("foo")); | |
| 74 webkit_glue::IDBKeysFromValuesAndKeyPath( | |
| 75 serialized_values, key_path, &values); | |
| 76 | |
| 77 ASSERT_EQ(size_t(4), values.size()); | |
| 78 ASSERT_EQ(WebKit::WebIDBKey::StringType, values[0].type()); | |
| 79 ASSERT_EQ(UTF8ToUTF16("zoo"), values[0].string()); | |
| 80 ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type()); | |
| 81 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[2].type()); | |
| 82 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[3].type()); | |
| 83 | |
| 84 values.clear(); | |
| 85 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
| 86 webkit_glue::IDBKeysFromValuesAndKeyPath( | |
| 87 serialized_values, key_path, &values); | |
| 88 | |
| 89 ASSERT_EQ(size_t(4), values.size()); | |
| 90 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[0].type()); | |
| 91 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[1].type()); | |
| 92 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[2].type()); | |
| 93 ASSERT_EQ(WebKit::WebIDBKey::NullType, values[3].type()); | |
| 94 | |
| 95 values.clear(); | |
| 96 key_path.SetString(UTF8ToUTF16("!+Invalid[KeyPath[[[")); | |
| 97 ASSERT_FALSE(key_path.IsValid()); | |
| 98 } | |
| 99 | |
| 100 class IDBKeyPathHelper : public UtilityProcessHostClient { | |
| 101 public: | |
| 102 IDBKeyPathHelper() | |
| 103 : expected_id_(0), | |
| 104 value_for_key_path_failed_(false) { | |
| 105 } | |
| 106 | |
| 107 void CreateUtilityProcess() { | |
| 108 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 109 BrowserThread::PostTask( | |
| 110 BrowserThread::IO, FROM_HERE, | |
| 111 base::Bind(&IDBKeyPathHelper::CreateUtilityProcess, this)); | |
| 112 return; | |
| 113 } | |
| 114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 115 utility_process_host_ = | |
| 116 (new UtilityProcessHostImpl(this, BrowserThread::IO))->AsWeakPtr(); | |
| 117 utility_process_host_->EnableZygote(); | |
| 118 utility_process_host_->StartBatchMode(); | |
| 119 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 120 MessageLoop::QuitClosure()); | |
| 121 } | |
| 122 | |
| 123 void DestroyUtilityProcess() { | |
| 124 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 125 BrowserThread::PostTask( | |
| 126 BrowserThread::IO, FROM_HERE, | |
| 127 base::Bind(&IDBKeyPathHelper::DestroyUtilityProcess, this)); | |
| 128 return; | |
| 129 } | |
| 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 131 utility_process_host_->EndBatchMode(); | |
| 132 utility_process_host_.reset(); | |
| 133 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 134 MessageLoop::QuitClosure()); | |
| 135 } | |
| 136 | |
| 137 void SetExpectedKeys(int expected_id, | |
| 138 const std::vector<IndexedDBKey>& expected_keys, | |
| 139 bool failed) { | |
| 140 expected_id_ = expected_id; | |
| 141 expected_keys_ = expected_keys; | |
| 142 value_for_key_path_failed_ = failed; | |
| 143 } | |
| 144 | |
| 145 void SetExpectedValue(const SerializedScriptValue& expected_value) { | |
| 146 expected_value_ = expected_value; | |
| 147 } | |
| 148 | |
| 149 void CheckValuesForKeyPath( | |
| 150 int id, | |
| 151 const std::vector<SerializedScriptValue>& serialized_values, | |
| 152 const IndexedDBKeyPath& key_path) { | |
| 153 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 154 BrowserThread::PostTask( | |
| 155 BrowserThread::IO, FROM_HERE, | |
| 156 base::Bind(&IDBKeyPathHelper::CheckValuesForKeyPath, this, id, | |
| 157 serialized_values, key_path)); | |
| 158 return; | |
| 159 } | |
| 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 161 bool ret = utility_process_host_->Send( | |
| 162 new UtilityMsg_IDBKeysFromValuesAndKeyPath( | |
| 163 id, serialized_values, key_path)); | |
| 164 ASSERT_TRUE(ret); | |
| 165 } | |
| 166 | |
| 167 void CheckInjectValue(const IndexedDBKey& key, | |
| 168 const SerializedScriptValue& value, | |
| 169 const IndexedDBKeyPath& key_path) { | |
| 170 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 171 BrowserThread::PostTask( | |
| 172 BrowserThread::IO, FROM_HERE, | |
| 173 base::Bind(&IDBKeyPathHelper::CheckInjectValue, this, key, value, | |
| 174 key_path)); | |
| 175 return; | |
| 176 } | |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 178 bool ret = utility_process_host_->Send(new UtilityMsg_InjectIDBKey( | |
| 179 key, value, key_path)); | |
| 180 ASSERT_TRUE(ret); | |
| 181 } | |
| 182 | |
| 183 // UtilityProcessHostClient | |
| 184 bool OnMessageReceived(const IPC::Message& message) { | |
| 185 bool msg_is_ok = true; | |
| 186 bool handled = true; | |
| 187 IPC_BEGIN_MESSAGE_MAP_EX(IDBKeyPathHelper, message, msg_is_ok) | |
| 188 IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded, | |
| 189 OnIDBKeysFromValuesAndKeyPathSucceeded) | |
| 190 IPC_MESSAGE_HANDLER(UtilityHostMsg_InjectIDBKey_Finished, | |
| 191 OnInjectIDBKeyFinished) | |
| 192 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 193 IPC_END_MESSAGE_MAP_EX() | |
| 194 return handled; | |
| 195 } | |
| 196 | |
| 197 void OnIDBKeysFromValuesAndKeyPathSucceeded( | |
| 198 int id, const std::vector<IndexedDBKey>& values) { | |
| 199 EXPECT_EQ(expected_id_, id); | |
| 200 EXPECT_FALSE(value_for_key_path_failed_); | |
| 201 ASSERT_EQ(expected_keys_.size(), values.size()); | |
| 202 size_t pos = 0; | |
| 203 for (std::vector<IndexedDBKey>::const_iterator i(values.begin()); | |
| 204 i != values.end(); ++i, ++pos) { | |
| 205 ASSERT_EQ(expected_keys_[pos].type(), i->type()); | |
| 206 if (i->type() == WebKit::WebIDBKey::StringType) { | |
| 207 ASSERT_EQ(expected_keys_[pos].string(), i->string()); | |
| 208 } else if (i->type() == WebKit::WebIDBKey::NumberType) { | |
| 209 ASSERT_EQ(expected_keys_[pos].number(), i->number()); | |
| 210 } | |
| 211 } | |
| 212 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 213 MessageLoop::QuitClosure()); | |
| 214 } | |
| 215 | |
| 216 void OnIDBKeysFromValuesAndKeyPathFailed(int id) { | |
| 217 EXPECT_TRUE(value_for_key_path_failed_); | |
| 218 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 219 MessageLoop::QuitClosure()); | |
| 220 } | |
| 221 | |
| 222 void OnInjectIDBKeyFinished(const SerializedScriptValue& new_value) { | |
| 223 EXPECT_EQ(expected_value_.data(), new_value.data()); | |
| 224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 225 MessageLoop::QuitClosure()); | |
| 226 } | |
| 227 | |
| 228 | |
| 229 private: | |
| 230 virtual ~IDBKeyPathHelper() {} | |
| 231 | |
| 232 int expected_id_; | |
| 233 std::vector<IndexedDBKey> expected_keys_; | |
| 234 base::WeakPtr<UtilityProcessHost> utility_process_host_; | |
| 235 bool value_for_key_path_failed_; | |
| 236 SerializedScriptValue expected_value_; | |
| 237 }; | |
| 238 | |
| 239 // This test fixture runs in the UI thread. However, most of the work done by | |
| 240 // UtilityProcessHost (and wrapped by IDBKeyPathHelper above) happens on the IO | |
| 241 // thread. This fixture delegates to IDBKeyPathHelper and blocks via | |
| 242 // "RunMessageLoop()", until IDBKeyPathHelper posts a quit | |
| 243 // message the MessageLoop. | |
| 244 class ScopedIDBKeyPathHelper { | |
| 245 public: | |
| 246 ScopedIDBKeyPathHelper() { | |
| 247 key_path_helper_ = new IDBKeyPathHelper(); | |
| 248 key_path_helper_->CreateUtilityProcess(); | |
| 249 RunMessageLoop(); | |
| 250 } | |
| 251 | |
| 252 ~ScopedIDBKeyPathHelper() { | |
| 253 key_path_helper_->DestroyUtilityProcess(); | |
| 254 RunMessageLoop(); | |
| 255 } | |
| 256 | |
| 257 void SetExpectedKeys(int id, | |
| 258 const std::vector<IndexedDBKey>& expected_keys, | |
| 259 bool failed) { | |
| 260 key_path_helper_->SetExpectedKeys(id, expected_keys, failed); | |
| 261 } | |
| 262 | |
| 263 void SetExpectedValue(const SerializedScriptValue& expected_value) { | |
| 264 key_path_helper_->SetExpectedValue(expected_value); | |
| 265 } | |
| 266 | |
| 267 void CheckValuesForKeyPath( | |
| 268 int id, | |
| 269 const std::vector<SerializedScriptValue>& | |
| 270 serialized_script_values, | |
| 271 const IndexedDBKeyPath& key_path) { | |
| 272 key_path_helper_->CheckValuesForKeyPath(id, serialized_script_values, | |
| 273 key_path); | |
| 274 RunMessageLoop(); | |
| 275 } | |
| 276 | |
| 277 void CheckInjectValue(const IndexedDBKey& key, | |
| 278 const SerializedScriptValue& value, | |
| 279 const IndexedDBKeyPath& key_path) { | |
| 280 key_path_helper_->CheckInjectValue(key, value, key_path); | |
| 281 RunMessageLoop(); | |
| 282 } | |
| 283 | |
| 284 private: | |
| 285 scoped_refptr<IDBKeyPathHelper> key_path_helper_; | |
| 286 }; | |
| 287 | |
| 288 // Cases: | |
| 289 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathExtract) { | |
| 290 ScopedIDBKeyPathHelper scoped_helper; | |
| 291 const int kId = 7; | |
| 292 std::vector<IndexedDBKey> expected_keys; | |
| 293 std::vector<SerializedScriptValue> serialized_values; | |
| 294 | |
| 295 IndexedDBKey string_zoo_key; | |
| 296 string_zoo_key.SetString(UTF8ToUTF16("zoo")); | |
| 297 IndexedDBKey null_key; | |
| 298 null_key.SetNull(); | |
| 299 IndexedDBKey invalid_key; | |
| 300 invalid_key.SetInvalid(); | |
| 301 | |
| 302 // keypath: "foo", value: {foo: "zoo"}, expected: "zoo" | |
| 303 char16 data_foo_zoo[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
| 304 serialized_values.push_back(SerializedScriptValue( | |
| 305 false, false, string16(data_foo_zoo, arraysize(data_foo_zoo)))); | |
| 306 expected_keys.push_back(string_zoo_key); | |
| 307 | |
| 308 // keypath: "foo", value: {foo: null}, expected: invalid | |
| 309 char16 data_foo_null[] = {0x0353, 0x6f66, 0x306f, 0x017b}; | |
| 310 serialized_values.push_back(SerializedScriptValue( | |
| 311 false, false, string16(data_foo_null, arraysize(data_foo_null)))); | |
| 312 expected_keys.push_back(invalid_key); | |
| 313 | |
| 314 // keypath: "foo", value: {}, expected: null | |
| 315 char16 data_object[] = {0x017b}; | |
| 316 serialized_values.push_back(SerializedScriptValue( | |
| 317 false, false, string16(data_object, arraysize(data_object)))); | |
| 318 expected_keys.push_back(null_key); | |
| 319 | |
| 320 // keypath: "foo", value: null, expected: null | |
| 321 serialized_values.push_back( | |
| 322 SerializedScriptValue(true, false, string16())); | |
| 323 expected_keys.push_back(null_key); | |
| 324 | |
| 325 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
| 326 | |
| 327 IndexedDBKeyPath key_path; | |
| 328 key_path.SetString(UTF8ToUTF16("foo")); | |
| 329 scoped_helper.CheckValuesForKeyPath( | |
| 330 kId, serialized_values, key_path); | |
| 331 } | |
| 332 | |
| 333 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathPropertyNotAvailable) { | |
| 334 ScopedIDBKeyPathHelper scoped_helper; | |
| 335 const int kId = 7; | |
| 336 std::vector<IndexedDBKey> expected_keys; | |
| 337 IndexedDBKey null_value; | |
| 338 null_value.SetNull(); | |
| 339 expected_keys.push_back(null_value); | |
| 340 expected_keys.push_back(null_value); | |
| 341 | |
| 342 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
| 343 | |
| 344 std::vector<SerializedScriptValue> serialized_values; | |
| 345 // {foo: "zoo", bar: null} | |
| 346 char16 data[] = {0x0353, 0x6f66, 0x536f, 0x7a03, 0x6f6f, 0x0353, 0x6162, | |
| 347 0x3072, 0x027b}; | |
| 348 serialized_values.push_back(SerializedScriptValue( | |
| 349 false, false, string16(data, arraysize(data)))); | |
| 350 | |
| 351 // null | |
| 352 serialized_values.push_back( | |
| 353 SerializedScriptValue(true, false, string16())); | |
| 354 | |
| 355 IndexedDBKeyPath key_path; | |
| 356 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
| 357 scoped_helper.CheckValuesForKeyPath(kId, serialized_values, key_path); | |
| 358 } | |
| 359 | |
| 360 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, IDBKeyPathMultipleCalls) { | |
| 361 ScopedIDBKeyPathHelper scoped_helper; | |
| 362 const int kId = 7; | |
| 363 std::vector<IndexedDBKey> expected_keys; | |
| 364 | |
| 365 IndexedDBKey null_value; | |
| 366 null_value.SetNull(); | |
| 367 expected_keys.push_back(null_value); | |
| 368 expected_keys.push_back(null_value); | |
| 369 scoped_helper.SetExpectedKeys(kId, expected_keys, false); | |
| 370 | |
| 371 std::vector<SerializedScriptValue> serialized_values; | |
| 372 | |
| 373 // {foo: "zoo", bar: null} | |
| 374 char16 data[] = {0x0353, 0x6f66, 0x536f, 0x7a03, 0x6f6f, 0x0353, 0x6162, | |
| 375 0x3072, 0x027b}; | |
| 376 serialized_values.push_back(SerializedScriptValue( | |
| 377 false, false, string16(data, arraysize(data)))); | |
| 378 | |
| 379 // null | |
| 380 serialized_values.push_back( | |
| 381 SerializedScriptValue(true, false, string16())); | |
| 382 | |
| 383 IndexedDBKeyPath key_path; | |
| 384 key_path.SetString(UTF8ToUTF16("PropertyNotAvailable")); | |
| 385 scoped_helper.CheckValuesForKeyPath(kId, serialized_values, key_path); | |
| 386 | |
| 387 // Call again with the Utility process in batch mode and with valid keys. | |
| 388 expected_keys.clear(); | |
| 389 IndexedDBKey value; | |
| 390 value.SetString(UTF8ToUTF16("zoo")); | |
| 391 expected_keys.push_back(value); | |
| 392 expected_keys.push_back(null_value); | |
| 393 scoped_helper.SetExpectedKeys(kId + 1, expected_keys, false); | |
| 394 key_path.SetString(UTF8ToUTF16("foo")); | |
| 395 scoped_helper.CheckValuesForKeyPath(kId + 1, serialized_values, key_path); | |
| 396 } | |
| 397 | |
| 398 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, InjectIDBKey) { | |
| 399 // {foo: 'zoo'} | |
| 400 const char16 initial_data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b}; | |
| 401 SerializedScriptValue value( | |
| 402 false, false, string16(initial_data, arraysize(initial_data))); | |
| 403 IndexedDBKey key; | |
| 404 key.SetString(UTF8ToUTF16("myNewKey")); | |
| 405 | |
| 406 ScopedIDBKeyPathHelper scoped_helper; | |
| 407 | |
| 408 // {foo: 'zoo', bar: 'myNewKey'} | |
| 409 const char16 expected_data[] = {0x01ff, 0x003f, 0x3f6f, 0x5301, 0x6603, | |
| 410 0x6f6f, 0x013f, 0x0353, 0x6f7a, 0x3f6f, | |
| 411 0x5301, 0x6203, 0x7261, 0x013f, 0x0853, | |
| 412 0x796d, 0x654e, 0x4b77, 0x7965, 0x027b}; | |
| 413 SerializedScriptValue expected_value( | |
| 414 false, false, string16(expected_data, arraysize(expected_data))); | |
| 415 scoped_helper.SetExpectedValue(expected_value); | |
| 416 IndexedDBKeyPath key_path; | |
| 417 key_path.SetString(UTF8ToUTF16("bar")); | |
| 418 scoped_helper.CheckInjectValue(key, value, key_path); | |
| 419 | |
| 420 // Should fail - can't apply properties to string value of key foo | |
| 421 const SerializedScriptValue failure_value; | |
| 422 scoped_helper.SetExpectedValue(failure_value); | |
| 423 key_path.SetString(UTF8ToUTF16("foo.bad.path")); | |
| 424 scoped_helper.CheckInjectValue(key, value, key_path); | |
| 425 | |
| 426 // {foo: 'zoo', bar: {baz: 'myNewKey'}} | |
| 427 const char16 expected_data2[] = {0x01ff, 0x003f, 0x3f6f, 0x5301, 0x6603, | |
| 428 0x6f6f, 0x013f, 0x0353, 0x6f7a, 0x3f6f, | |
| 429 0x5301, 0x6203, 0x7261, 0x013f, 0x3f6f, | |
| 430 0x5302, 0x6203, 0x7a61, 0x023f, 0x0853, | |
| 431 0x796d, 0x654e, 0x4b77, 0x7965, 0x017b, | |
| 432 0x027b}; | |
| 433 SerializedScriptValue expected_value2( | |
| 434 false, false, string16(expected_data2, arraysize(expected_data2))); | |
| 435 scoped_helper.SetExpectedValue(expected_value2); | |
| 436 key_path.SetString(UTF8ToUTF16("bar.baz")); | |
| 437 scoped_helper.CheckInjectValue(key, value, key_path); | |
| 438 } | |
| 439 | |
| 440 } // namespace content | |
| OLD | NEW |