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 "chrome/test/webdriver/webdriver_util.h" 6 7 #include "base/base64.h" 8 #include "base/basictypes.h" 9 #include "base/file_util.h" 10 #include "base/files/file_enumerator.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/format_macros.h" 13 #include "base/json/json_reader.h" 14 #include "base/json/json_writer.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/rand_util.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_split.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/stringprintf.h" 21 #include "base/third_party/icu/icu_utf.h" 22 #include "chrome/common/automation_id.h" 23 #include "chrome/test/automation/automation_json_requests.h" 24 #include "third_party/zlib/google/zip.h" 25 26 using base::DictionaryValue; 27 using base::ListValue; 28 using base::Value; 29 30 namespace webdriver { 31 32 SkipParsing* kSkipParsing = NULL; 33 34 std::string GenerateRandomID() { 35 uint64 msb = base::RandUint64(); 36 uint64 lsb = base::RandUint64(); 37 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb); 38 } 39 40 bool Base64Decode(const std::string& base64, 41 std::string* bytes) { 42 std::string copy = base64; 43 // Some WebDriver client base64 encoders follow RFC 1521, which require that 44 // 'encoded lines be no more than 76 characters long'. Just remove any 45 // newlines. 46 RemoveChars(copy, "\n", ©); 47 return base::Base64Decode(copy, bytes); 48 } 49 50 namespace { 51 52 bool UnzipArchive(const base::FilePath& unzip_dir, 53 const std::string& bytes, 54 std::string* error_msg) { 55 base::ScopedTempDir dir; 56 if (!dir.CreateUniqueTempDir()) { 57 *error_msg = "Unable to create temp dir"; 58 return false; 59 } 60 base::FilePath archive = dir.path().AppendASCII("temp.zip"); 61 int length = bytes.length(); 62 if (file_util::WriteFile(archive, bytes.c_str(), length) != length) { 63 *error_msg = "Could not write file to temp dir"; 64 return false; 65 } 66 if (!zip::Unzip(archive, unzip_dir)) { 67 *error_msg = "Could not unzip archive"; 68 return false; 69 } 70 return true; 71 } 72 73 } // namespace 74 75 bool Base64DecodeAndUnzip(const base::FilePath& unzip_dir, 76 const std::string& base64, 77 std::string* error_msg) { 78 std::string zip_data; 79 if (!Base64Decode(base64, &zip_data)) { 80 *error_msg = "Could not decode base64 zip data"; 81 return false; 82 } 83 return UnzipArchive(unzip_dir, zip_data, error_msg); 84 } 85 86 namespace { 87 88 // Stream for writing binary data. 89 class DataOutputStream { 90 public: 91 DataOutputStream() {} 92 ~DataOutputStream() {} 93 94 void WriteUInt16(uint16 data) { 95 WriteBytes(&data, sizeof(data)); 96 } 97 98 void WriteUInt32(uint32 data) { 99 WriteBytes(&data, sizeof(data)); 100 } 101 102 void WriteString(const std::string& data) { 103 WriteBytes(data.c_str(), data.length()); 104 } 105 106 void WriteBytes(const void* bytes, int size) { 107 size_t next = buffer_.length(); 108 buffer_.resize(next + size); 109 memcpy(&buffer_[next], bytes, size); 110 } 111 112 const std::string& buffer() const { return buffer_; } 113 114 private: 115 std::string buffer_; 116 }; 117 118 // Stream for reading binary data. 119 class DataInputStream { 120 public: 121 DataInputStream(const char* data, int size) 122 : data_(data), size_(size), iter_(0) {} 123 ~DataInputStream() {} 124 125 bool ReadUInt16(uint16* data) { 126 return ReadBytes(data, sizeof(*data)); 127 } 128 129 bool ReadUInt32(uint32* data) { 130 return ReadBytes(data, sizeof(*data)); 131 } 132 133 bool ReadString(std::string* data, int length) { 134 if (length < 0) 135 return false; 136 // Check here to make sure we don't allocate wastefully. 137 if (iter_ + length > size_) 138 return false; 139 data->resize(length); 140 return ReadBytes(&(*data)[0], length); 141 } 142 143 bool ReadBytes(void* bytes, int size) { 144 if (iter_ + size > size_) 145 return false; 146 memcpy(bytes, &data_[iter_], size); 147 iter_ += size; 148 return true; 149 } 150 151 int remaining() const { return size_ - iter_; } 152 153 private: 154 const char* data_; 155 int size_; 156 int iter_; 157 }; 158 159 // A file entry within a zip archive. This may be incomplete and is not 160 // guaranteed to be able to parse all types of zip entries. 161 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip 162 // file format. 163 struct ZipEntry { 164 // The given bytes must contain the whole zip entry and only the entry, 165 // although the entry may include a data descriptor. 166 static bool FromBytes(const std::string& bytes, ZipEntry* zip, 167 std::string* error_msg) { 168 DataInputStream stream(bytes.c_str(), bytes.length()); 169 170 uint32 signature; 171 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) { 172 *error_msg = "Invalid file header signature"; 173 return false; 174 } 175 if (!stream.ReadUInt16(&zip->version_needed)) { 176 *error_msg = "Invalid version"; 177 return false; 178 } 179 if (!stream.ReadUInt16(&zip->bit_flag)) { 180 *error_msg = "Invalid bit flag"; 181 return false; 182 } 183 if (!stream.ReadUInt16(&zip->compression_method)) { 184 *error_msg = "Invalid compression method"; 185 return false; 186 } 187 if (!stream.ReadUInt16(&zip->mod_time)) { 188 *error_msg = "Invalid file last modified time"; 189 return false; 190 } 191 if (!stream.ReadUInt16(&zip->mod_date)) { 192 *error_msg = "Invalid file last modified date"; 193 return false; 194 } 195 if (!stream.ReadUInt32(&zip->crc)) { 196 *error_msg = "Invalid crc"; 197 return false; 198 } 199 uint32 compressed_size; 200 if (!stream.ReadUInt32(&compressed_size)) { 201 *error_msg = "Invalid compressed size"; 202 return false; 203 } 204 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 205 *error_msg = "Invalid compressed size"; 206 return false; 207 } 208 uint16 name_length; 209 if (!stream.ReadUInt16(&name_length)) { 210 *error_msg = "Invalid name length"; 211 return false; 212 } 213 uint16 field_length; 214 if (!stream.ReadUInt16(&field_length)) { 215 *error_msg = "Invalid field length"; 216 return false; 217 } 218 if (!stream.ReadString(&zip->name, name_length)) { 219 *error_msg = "Invalid name"; 220 return false; 221 } 222 if (!stream.ReadString(&zip->fields, field_length)) { 223 *error_msg = "Invalid fields"; 224 return false; 225 } 226 if (zip->bit_flag & 0x8) { 227 // Has compressed data and a separate data descriptor. 228 if (stream.remaining() < 16) { 229 *error_msg = "Too small for data descriptor"; 230 return false; 231 } 232 compressed_size = stream.remaining() - 16; 233 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 234 *error_msg = "Invalid compressed data before descriptor"; 235 return false; 236 } 237 if (!stream.ReadUInt32(&signature) || 238 signature != kDataDescriptorSignature) { 239 *error_msg = "Invalid data descriptor signature"; 240 return false; 241 } 242 if (!stream.ReadUInt32(&zip->crc)) { 243 *error_msg = "Invalid crc"; 244 return false; 245 } 246 if (!stream.ReadUInt32(&compressed_size)) { 247 *error_msg = "Invalid compressed size"; 248 return false; 249 } 250 if (compressed_size != zip->compressed_data.length()) { 251 *error_msg = "Compressed data does not match data descriptor"; 252 return false; 253 } 254 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 255 *error_msg = "Invalid compressed size"; 256 return false; 257 } 258 } else { 259 // Just has compressed data. 260 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 261 *error_msg = "Invalid compressed data"; 262 return false; 263 } 264 if (stream.remaining() != 0) { 265 *error_msg = "Leftover data after zip entry"; 266 return false; 267 } 268 } 269 return true; 270 } 271 272 // Returns bytes for a valid zip file that just contains this zip entry. 273 std::string ToZip() { 274 // Write zip entry with no data descriptor. 275 DataOutputStream stream; 276 stream.WriteUInt32(kFileHeaderSignature); 277 stream.WriteUInt16(version_needed); 278 stream.WriteUInt16(bit_flag); 279 stream.WriteUInt16(compression_method); 280 stream.WriteUInt16(mod_time); 281 stream.WriteUInt16(mod_date); 282 stream.WriteUInt32(crc); 283 stream.WriteUInt32(compressed_data.length()); 284 stream.WriteUInt32(uncompressed_size); 285 stream.WriteUInt16(name.length()); 286 stream.WriteUInt16(fields.length()); 287 stream.WriteString(name); 288 stream.WriteString(fields); 289 stream.WriteString(compressed_data); 290 uint32 entry_size = stream.buffer().length(); 291 292 // Write central directory. 293 stream.WriteUInt32(kCentralDirSignature); 294 stream.WriteUInt16(0x14); // Version made by. Unused at version 0. 295 stream.WriteUInt16(version_needed); 296 stream.WriteUInt16(bit_flag); 297 stream.WriteUInt16(compression_method); 298 stream.WriteUInt16(mod_time); 299 stream.WriteUInt16(mod_date); 300 stream.WriteUInt32(crc); 301 stream.WriteUInt32(compressed_data.length()); 302 stream.WriteUInt32(uncompressed_size); 303 stream.WriteUInt16(name.length()); 304 stream.WriteUInt16(fields.length()); 305 stream.WriteUInt16(0); // Comment length. 306 stream.WriteUInt16(0); // Disk number where file starts. 307 stream.WriteUInt16(0); // Internal file attr. 308 stream.WriteUInt32(0); // External file attr. 309 stream.WriteUInt32(0); // Offset to file. 310 stream.WriteString(name); 311 stream.WriteString(fields); 312 uint32 cd_size = stream.buffer().length() - entry_size; 313 314 // End of central directory. 315 stream.WriteUInt32(kEndOfCentralDirSignature); 316 stream.WriteUInt16(0); // num of this disk 317 stream.WriteUInt16(0); // disk where cd starts 318 stream.WriteUInt16(1); // number of cds on this disk 319 stream.WriteUInt16(1); // total cds 320 stream.WriteUInt32(cd_size); // size of cd 321 stream.WriteUInt32(entry_size); // offset of cd 322 stream.WriteUInt16(0); // comment len 323 324 return stream.buffer(); 325 } 326 327 static const uint32 kFileHeaderSignature; 328 static const uint32 kDataDescriptorSignature; 329 static const uint32 kCentralDirSignature; 330 static const uint32 kEndOfCentralDirSignature; 331 uint16 version_needed; 332 uint16 bit_flag; 333 uint16 compression_method; 334 uint16 mod_time; 335 uint16 mod_date; 336 uint32 crc; 337 uint32 uncompressed_size; 338 std::string name; 339 std::string fields; 340 std::string compressed_data; 341 }; 342 343 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50; 344 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50; 345 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50; 346 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50; 347 348 bool UnzipEntry(const base::FilePath& unzip_dir, 349 const std::string& bytes, 350 std::string* error_msg) { 351 ZipEntry entry; 352 std::string zip_error_msg; 353 if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg)) { 354 *error_msg = "Error while reading zip entry: " + zip_error_msg; 355 return false; 356 } 357 std::string archive = entry.ToZip(); 358 return UnzipArchive(unzip_dir, archive, error_msg); 359 } 360 361 } // namespace 362 363 bool UnzipSoleFile(const base::FilePath& unzip_dir, 364 const std::string& bytes, 365 base::FilePath* file, 366 std::string* error_msg) { 367 std::string archive_error, entry_error; 368 if (!UnzipArchive(unzip_dir, bytes, &archive_error) && 369 !UnzipEntry(unzip_dir, bytes, &entry_error)) { 370 *error_msg = base::StringPrintf( 371 "Failed to unzip file: Archive error: (%s) Entry error: (%s)", 372 archive_error.c_str(), entry_error.c_str()); 373 return false; 374 } 375 376 base::FileEnumerator enumerator(unzip_dir, false /* recursive */, 377 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); 378 base::FilePath first_file = enumerator.Next(); 379 if (first_file.empty()) { 380 *error_msg = "Zip contained 0 files"; 381 return false; 382 } 383 base::FilePath second_file = enumerator.Next(); 384 if (!second_file.empty()) { 385 *error_msg = "Zip contained multiple files"; 386 return false; 387 } 388 *file = first_file; 389 return true; 390 } 391 392 std::string JsonStringify(const Value* value) { 393 std::string json; 394 base::JSONWriter::Write(value, &json); 395 return json; 396 } 397 398 namespace { 399 400 // Truncates the given string to 100 characters, adding an ellipsis if 401 // truncation was necessary. 402 void TruncateString(std::string* data) { 403 const size_t kMaxLength = 100; 404 if (data->length() > kMaxLength) { 405 data->resize(kMaxLength); 406 data->replace(kMaxLength - 3, 3, "..."); 407 } 408 } 409 410 // Truncates all strings contained in the given value. 411 void TruncateContainedStrings(Value* value) { 412 ListValue* list = NULL; 413 DictionaryValue* dict = NULL; 414 if (value->GetAsDictionary(&dict)) { 415 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { 416 std::string data; 417 if (it.value().GetAsString(&data)) { 418 TruncateString(&data); 419 dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data)); 420 } else { 421 Value* child = NULL; 422 dict->GetWithoutPathExpansion(it.key(), &child); 423 TruncateContainedStrings(child); 424 } 425 } 426 } else if (value->GetAsList(&list)) { 427 for (size_t i = 0; i < list->GetSize(); ++i) { 428 Value* child; 429 if (!list->Get(i, &child)) 430 continue; 431 std::string data; 432 if (child->GetAsString(&data)) { 433 TruncateString(&data); 434 list->Set(i, new base::StringValue(data)); 435 } else { 436 TruncateContainedStrings(child); 437 } 438 } 439 } 440 } 441 442 } // namespace 443 444 std::string JsonStringifyForDisplay(const Value* value) { 445 scoped_ptr<Value> copy; 446 if (value->IsType(Value::TYPE_STRING)) { 447 std::string data; 448 value->GetAsString(&data); 449 TruncateString(&data); 450 copy.reset(new base::StringValue(data)); 451 } else { 452 copy.reset(value->DeepCopy()); 453 TruncateContainedStrings(copy.get()); 454 } 455 std::string json; 456 base::JSONWriter::WriteWithOptions(copy.get(), 457 base::JSONWriter::OPTIONS_PRETTY_PRINT, 458 &json); 459 return json; 460 } 461 462 const char* GetJsonTypeName(Value::Type type) { 463 switch (type) { 464 case Value::TYPE_NULL: 465 return "null"; 466 case Value::TYPE_BOOLEAN: 467 return "boolean"; 468 case Value::TYPE_INTEGER: 469 return "integer"; 470 case Value::TYPE_DOUBLE: 471 return "double"; 472 case Value::TYPE_STRING: 473 return "string"; 474 case Value::TYPE_BINARY: 475 return "binary"; 476 case Value::TYPE_DICTIONARY: 477 return "dictionary"; 478 case Value::TYPE_LIST: 479 return "list"; 480 } 481 return "unknown"; 482 } 483 484 std::string AutomationIdToString(const AutomationId& id) { 485 return base::StringPrintf("%d-%s", id.type(), id.id().c_str()); 486 } 487 488 bool StringToAutomationId(const std::string& string_id, AutomationId* id) { 489 std::vector<std::string> split_id; 490 base::SplitString(string_id, '-', &split_id); 491 if (split_id.size() != 2) 492 return false; 493 int type; 494 if (!base::StringToInt(split_id[0], &type)) 495 return false; 496 *id = AutomationId(static_cast<AutomationId::Type>(type), split_id[1]); 497 return true; 498 } 499 500 std::string WebViewIdToString(const WebViewId& view_id) { 501 return base::StringPrintf( 502 "%s%s", 503 view_id.old_style() ? "t" : "f", 504 AutomationIdToString(view_id.GetId()).c_str()); 505 } 506 507 bool StringToWebViewId(const std::string& string_id, WebViewId* view_id) { 508 if (string_id.empty() || (string_id[0] != 'f' && string_id[0] != 't')) 509 return false; 510 bool old_style = string_id[0] == 't'; 511 AutomationId id; 512 if (!StringToAutomationId(string_id.substr(1), &id)) 513 return false; 514 515 if (old_style) { 516 int tab_id; 517 if (!base::StringToInt(id.id(), &tab_id)) 518 return false; 519 *view_id = WebViewId::ForOldStyleTab(tab_id); 520 } else { 521 *view_id = WebViewId::ForView(id); 522 } 523 return true; 524 } 525 526 Error* FlattenStringArray(const ListValue* src, string16* dest) { 527 string16 keys; 528 for (size_t i = 0; i < src->GetSize(); ++i) { 529 string16 keys_list_part; 530 src->GetString(i, &keys_list_part); 531 for (size_t j = 0; j < keys_list_part.size(); ++j) { 532 if (CBU16_IS_SURROGATE(keys_list_part[j])) { 533 return new Error(kBadRequest, 534 "ChromeDriver only supports characters in the BMP"); 535 } 536 } 537 keys.append(keys_list_part); 538 } 539 *dest = keys; 540 return NULL; 541 } 542 543 ValueParser::ValueParser() { } 544 545 ValueParser::~ValueParser() { } 546 547 } // namespace webdriver 548 549 bool ValueConversionTraits<webdriver::SkipParsing>::SetFromValue( 550 const Value* value, const webdriver::SkipParsing* t) { 551 return true; 552 } 553 554 bool ValueConversionTraits<webdriver::SkipParsing>::CanConvert( 555 const Value* value) { 556 return true; 557 } 558