1 // Copyright (c) 2013 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/chromedriver/util.h" 6 7 #include "base/base64.h" 8 #include "base/file_util.h" 9 #include "base/files/file_enumerator.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/format_macros.h" 12 #include "base/rand_util.h" 13 #include "base/strings/string16.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/third_party/icu/icu_utf.h" 17 #include "base/values.h" 18 #include "chrome/test/chromedriver/chrome/status.h" 19 #include "chrome/test/chromedriver/chrome/ui_events.h" 20 #include "chrome/test/chromedriver/chrome/web_view.h" 21 #include "chrome/test/chromedriver/chrome/zip.h" 22 #include "chrome/test/chromedriver/key_converter.h" 23 24 std::string GenerateId() { 25 uint64 msb = base::RandUint64(); 26 uint64 lsb = base::RandUint64(); 27 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb); 28 } 29 30 namespace { 31 32 Status FlattenStringArray(const base::ListValue* src, string16* dest) { 33 string16 keys; 34 for (size_t i = 0; i < src->GetSize(); ++i) { 35 string16 keys_list_part; 36 if (!src->GetString(i, &keys_list_part)) 37 return Status(kUnknownError, "keys should be a string"); 38 for (size_t j = 0; j < keys_list_part.size(); ++j) { 39 if (CBU16_IS_SURROGATE(keys_list_part[j])) { 40 return Status(kUnknownError, 41 "ChromeDriver only supports characters in the BMP"); 42 } 43 } 44 keys.append(keys_list_part); 45 } 46 *dest = keys; 47 return Status(kOk); 48 } 49 50 } // namespace 51 52 Status SendKeysOnWindow( 53 WebView* web_view, 54 const base::ListValue* key_list, 55 bool release_modifiers, 56 int* sticky_modifiers) { 57 string16 keys; 58 Status status = FlattenStringArray(key_list, &keys); 59 if (status.IsError()) 60 return status; 61 std::list<KeyEvent> events; 62 int sticky_modifiers_tmp = *sticky_modifiers; 63 status = ConvertKeysToKeyEvents( 64 keys, release_modifiers, &sticky_modifiers_tmp, &events); 65 if (status.IsError()) 66 return status; 67 status = web_view->DispatchKeyEvents(events); 68 if (status.IsOk()) 69 *sticky_modifiers = sticky_modifiers_tmp; 70 return status; 71 } 72 73 bool Base64Decode(const std::string& base64, 74 std::string* bytes) { 75 std::string copy = base64; 76 // Some WebDriver client base64 encoders follow RFC 1521, which require that 77 // 'encoded lines be no more than 76 characters long'. Just remove any 78 // newlines. 79 base::RemoveChars(copy, "\n", ©); 80 return base::Base64Decode(copy, bytes); 81 } 82 83 namespace { 84 85 Status UnzipArchive(const base::FilePath& unzip_dir, 86 const std::string& bytes) { 87 base::ScopedTempDir dir; 88 if (!dir.CreateUniqueTempDir()) 89 return Status(kUnknownError, "unable to create temp dir"); 90 91 base::FilePath archive = dir.path().AppendASCII("temp.zip"); 92 int length = bytes.length(); 93 if (file_util::WriteFile(archive, bytes.c_str(), length) != length) 94 return Status(kUnknownError, "could not write file to temp dir"); 95 96 if (!zip::Unzip(archive, unzip_dir)) 97 return Status(kUnknownError, "could not unzip archive"); 98 return Status(kOk); 99 } 100 101 // Stream for writing binary data. 102 class DataOutputStream { 103 public: 104 DataOutputStream() {} 105 ~DataOutputStream() {} 106 107 void WriteUInt16(uint16 data) { 108 WriteBytes(&data, sizeof(data)); 109 } 110 111 void WriteUInt32(uint32 data) { 112 WriteBytes(&data, sizeof(data)); 113 } 114 115 void WriteString(const std::string& data) { 116 WriteBytes(data.c_str(), data.length()); 117 } 118 119 void WriteBytes(const void* bytes, int size) { 120 if (!size) 121 return; 122 size_t next = buffer_.length(); 123 buffer_.resize(next + size); 124 memcpy(&buffer_[next], bytes, size); 125 } 126 127 const std::string& buffer() const { return buffer_; } 128 129 private: 130 std::string buffer_; 131 }; 132 133 // Stream for reading binary data. 134 class DataInputStream { 135 public: 136 DataInputStream(const char* data, int size) 137 : data_(data), size_(size), iter_(0) {} 138 ~DataInputStream() {} 139 140 bool ReadUInt16(uint16* data) { 141 return ReadBytes(data, sizeof(*data)); 142 } 143 144 bool ReadUInt32(uint32* data) { 145 return ReadBytes(data, sizeof(*data)); 146 } 147 148 bool ReadString(std::string* data, int length) { 149 if (length < 0) 150 return false; 151 // Check here to make sure we don't allocate wastefully. 152 if (iter_ + length > size_) 153 return false; 154 data->resize(length); 155 if (length == 0) 156 return true; 157 return ReadBytes(&(*data)[0], length); 158 } 159 160 bool ReadBytes(void* bytes, int size) { 161 if (iter_ + size > size_) 162 return false; 163 memcpy(bytes, &data_[iter_], size); 164 iter_ += size; 165 return true; 166 } 167 168 int remaining() const { return size_ - iter_; } 169 170 private: 171 const char* data_; 172 int size_; 173 int iter_; 174 }; 175 176 // A file entry within a zip archive. This may be incomplete and is not 177 // guaranteed to be able to parse all types of zip entries. 178 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip 179 // file format. 180 struct ZipEntry { 181 // The given bytes must contain the whole zip entry and only the entry, 182 // although the entry may include a data descriptor. 183 static bool FromBytes(const std::string& bytes, ZipEntry* zip, 184 std::string* error_msg) { 185 DataInputStream stream(bytes.c_str(), bytes.length()); 186 187 uint32 signature; 188 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) { 189 *error_msg = "invalid file header signature"; 190 return false; 191 } 192 if (!stream.ReadUInt16(&zip->version_needed)) { 193 *error_msg = "invalid version"; 194 return false; 195 } 196 if (!stream.ReadUInt16(&zip->bit_flag)) { 197 *error_msg = "invalid bit flag"; 198 return false; 199 } 200 if (!stream.ReadUInt16(&zip->compression_method)) { 201 *error_msg = "invalid compression method"; 202 return false; 203 } 204 if (!stream.ReadUInt16(&zip->mod_time)) { 205 *error_msg = "invalid file last modified time"; 206 return false; 207 } 208 if (!stream.ReadUInt16(&zip->mod_date)) { 209 *error_msg = "invalid file last modified date"; 210 return false; 211 } 212 if (!stream.ReadUInt32(&zip->crc)) { 213 *error_msg = "invalid crc"; 214 return false; 215 } 216 uint32 compressed_size; 217 if (!stream.ReadUInt32(&compressed_size)) { 218 *error_msg = "invalid compressed size"; 219 return false; 220 } 221 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 222 *error_msg = "invalid compressed size"; 223 return false; 224 } 225 uint16 name_length; 226 if (!stream.ReadUInt16(&name_length)) { 227 *error_msg = "invalid name length"; 228 return false; 229 } 230 uint16 field_length; 231 if (!stream.ReadUInt16(&field_length)) { 232 *error_msg = "invalid field length"; 233 return false; 234 } 235 if (!stream.ReadString(&zip->name, name_length)) { 236 *error_msg = "invalid name"; 237 return false; 238 } 239 if (!stream.ReadString(&zip->fields, field_length)) { 240 *error_msg = "invalid fields"; 241 return false; 242 } 243 if (zip->bit_flag & 0x8) { 244 // Has compressed data and a separate data descriptor. 245 if (stream.remaining() < 16) { 246 *error_msg = "too small for data descriptor"; 247 return false; 248 } 249 compressed_size = stream.remaining() - 16; 250 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 251 *error_msg = "invalid compressed data before descriptor"; 252 return false; 253 } 254 if (!stream.ReadUInt32(&signature) || 255 signature != kDataDescriptorSignature) { 256 *error_msg = "invalid data descriptor signature"; 257 return false; 258 } 259 if (!stream.ReadUInt32(&zip->crc)) { 260 *error_msg = "invalid crc"; 261 return false; 262 } 263 if (!stream.ReadUInt32(&compressed_size)) { 264 *error_msg = "invalid compressed size"; 265 return false; 266 } 267 if (compressed_size != zip->compressed_data.length()) { 268 *error_msg = "compressed data does not match data descriptor"; 269 return false; 270 } 271 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 272 *error_msg = "invalid compressed size"; 273 return false; 274 } 275 } else { 276 // Just has compressed data. 277 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 278 *error_msg = "invalid compressed data"; 279 return false; 280 } 281 if (stream.remaining() != 0) { 282 *error_msg = "leftover data after zip entry"; 283 return false; 284 } 285 } 286 return true; 287 } 288 289 // Returns bytes for a valid zip file that just contains this zip entry. 290 std::string ToZip() { 291 // Write zip entry with no data descriptor. 292 DataOutputStream stream; 293 stream.WriteUInt32(kFileHeaderSignature); 294 stream.WriteUInt16(version_needed); 295 stream.WriteUInt16(bit_flag); 296 stream.WriteUInt16(compression_method); 297 stream.WriteUInt16(mod_time); 298 stream.WriteUInt16(mod_date); 299 stream.WriteUInt32(crc); 300 stream.WriteUInt32(compressed_data.length()); 301 stream.WriteUInt32(uncompressed_size); 302 stream.WriteUInt16(name.length()); 303 stream.WriteUInt16(fields.length()); 304 stream.WriteString(name); 305 stream.WriteString(fields); 306 stream.WriteString(compressed_data); 307 uint32 entry_size = stream.buffer().length(); 308 309 // Write central directory. 310 stream.WriteUInt32(kCentralDirSignature); 311 stream.WriteUInt16(0x14); // Version made by. Unused at version 0. 312 stream.WriteUInt16(version_needed); 313 stream.WriteUInt16(bit_flag); 314 stream.WriteUInt16(compression_method); 315 stream.WriteUInt16(mod_time); 316 stream.WriteUInt16(mod_date); 317 stream.WriteUInt32(crc); 318 stream.WriteUInt32(compressed_data.length()); 319 stream.WriteUInt32(uncompressed_size); 320 stream.WriteUInt16(name.length()); 321 stream.WriteUInt16(fields.length()); 322 stream.WriteUInt16(0); // Comment length. 323 stream.WriteUInt16(0); // Disk number where file starts. 324 stream.WriteUInt16(0); // Internal file attr. 325 stream.WriteUInt32(0); // External file attr. 326 stream.WriteUInt32(0); // Offset to file. 327 stream.WriteString(name); 328 stream.WriteString(fields); 329 uint32 cd_size = stream.buffer().length() - entry_size; 330 331 // End of central directory. 332 stream.WriteUInt32(kEndOfCentralDirSignature); 333 stream.WriteUInt16(0); // num of this disk 334 stream.WriteUInt16(0); // disk where cd starts 335 stream.WriteUInt16(1); // number of cds on this disk 336 stream.WriteUInt16(1); // total cds 337 stream.WriteUInt32(cd_size); // size of cd 338 stream.WriteUInt32(entry_size); // offset of cd 339 stream.WriteUInt16(0); // comment len 340 341 return stream.buffer(); 342 } 343 344 static const uint32 kFileHeaderSignature; 345 static const uint32 kDataDescriptorSignature; 346 static const uint32 kCentralDirSignature; 347 static const uint32 kEndOfCentralDirSignature; 348 uint16 version_needed; 349 uint16 bit_flag; 350 uint16 compression_method; 351 uint16 mod_time; 352 uint16 mod_date; 353 uint32 crc; 354 uint32 uncompressed_size; 355 std::string name; 356 std::string fields; 357 std::string compressed_data; 358 }; 359 360 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50; 361 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50; 362 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50; 363 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50; 364 365 Status UnzipEntry(const base::FilePath& unzip_dir, 366 const std::string& bytes) { 367 ZipEntry entry; 368 std::string zip_error_msg; 369 if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg)) 370 return Status(kUnknownError, zip_error_msg); 371 std::string archive = entry.ToZip(); 372 return UnzipArchive(unzip_dir, archive); 373 } 374 375 } // namespace 376 377 Status UnzipSoleFile(const base::FilePath& unzip_dir, 378 const std::string& bytes, 379 base::FilePath* file) { 380 std::string archive_error, entry_error; 381 Status status = UnzipArchive(unzip_dir, bytes); 382 if (status.IsError()) { 383 Status entry_status = UnzipEntry(unzip_dir, bytes); 384 if (entry_status.IsError()) { 385 return Status(kUnknownError, base::StringPrintf( 386 "archive error: (%s), entry error: (%s)", 387 status.message().c_str(), entry_status.message().c_str())); 388 } 389 } 390 391 base::FileEnumerator enumerator(unzip_dir, false /* recursive */, 392 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); 393 base::FilePath first_file = enumerator.Next(); 394 if (first_file.empty()) 395 return Status(kUnknownError, "contained 0 files"); 396 397 base::FilePath second_file = enumerator.Next(); 398 if (!second_file.empty()) 399 return Status(kUnknownError, "contained multiple files"); 400 401 *file = first_file; 402 return Status(kOk); 403 } 404