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 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 size_t next = buffer_.length(); 121 buffer_.resize(next + size); 122 memcpy(&buffer_[next], bytes, size); 123 } 124 125 const std::string& buffer() const { return buffer_; } 126 127 private: 128 std::string buffer_; 129 }; 130 131 // Stream for reading binary data. 132 class DataInputStream { 133 public: 134 DataInputStream(const char* data, int size) 135 : data_(data), size_(size), iter_(0) {} 136 ~DataInputStream() {} 137 138 bool ReadUInt16(uint16* data) { 139 return ReadBytes(data, sizeof(*data)); 140 } 141 142 bool ReadUInt32(uint32* data) { 143 return ReadBytes(data, sizeof(*data)); 144 } 145 146 bool ReadString(std::string* data, int length) { 147 if (length < 0) 148 return false; 149 // Check here to make sure we don't allocate wastefully. 150 if (iter_ + length > size_) 151 return false; 152 data->resize(length); 153 return ReadBytes(&(*data)[0], length); 154 } 155 156 bool ReadBytes(void* bytes, int size) { 157 if (iter_ + size > size_) 158 return false; 159 memcpy(bytes, &data_[iter_], size); 160 iter_ += size; 161 return true; 162 } 163 164 int remaining() const { return size_ - iter_; } 165 166 private: 167 const char* data_; 168 int size_; 169 int iter_; 170 }; 171 172 // A file entry within a zip archive. This may be incomplete and is not 173 // guaranteed to be able to parse all types of zip entries. 174 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip 175 // file format. 176 struct ZipEntry { 177 // The given bytes must contain the whole zip entry and only the entry, 178 // although the entry may include a data descriptor. 179 static bool FromBytes(const std::string& bytes, ZipEntry* zip, 180 std::string* error_msg) { 181 DataInputStream stream(bytes.c_str(), bytes.length()); 182 183 uint32 signature; 184 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) { 185 *error_msg = "invalid file header signature"; 186 return false; 187 } 188 if (!stream.ReadUInt16(&zip->version_needed)) { 189 *error_msg = "invalid version"; 190 return false; 191 } 192 if (!stream.ReadUInt16(&zip->bit_flag)) { 193 *error_msg = "invalid bit flag"; 194 return false; 195 } 196 if (!stream.ReadUInt16(&zip->compression_method)) { 197 *error_msg = "invalid compression method"; 198 return false; 199 } 200 if (!stream.ReadUInt16(&zip->mod_time)) { 201 *error_msg = "invalid file last modified time"; 202 return false; 203 } 204 if (!stream.ReadUInt16(&zip->mod_date)) { 205 *error_msg = "invalid file last modified date"; 206 return false; 207 } 208 if (!stream.ReadUInt32(&zip->crc)) { 209 *error_msg = "invalid crc"; 210 return false; 211 } 212 uint32 compressed_size; 213 if (!stream.ReadUInt32(&compressed_size)) { 214 *error_msg = "invalid compressed size"; 215 return false; 216 } 217 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 218 *error_msg = "invalid compressed size"; 219 return false; 220 } 221 uint16 name_length; 222 if (!stream.ReadUInt16(&name_length)) { 223 *error_msg = "invalid name length"; 224 return false; 225 } 226 uint16 field_length; 227 if (!stream.ReadUInt16(&field_length)) { 228 *error_msg = "invalid field length"; 229 return false; 230 } 231 if (!stream.ReadString(&zip->name, name_length)) { 232 *error_msg = "invalid name"; 233 return false; 234 } 235 if (!stream.ReadString(&zip->fields, field_length)) { 236 *error_msg = "invalid fields"; 237 return false; 238 } 239 if (zip->bit_flag & 0x8) { 240 // Has compressed data and a separate data descriptor. 241 if (stream.remaining() < 16) { 242 *error_msg = "too small for data descriptor"; 243 return false; 244 } 245 compressed_size = stream.remaining() - 16; 246 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 247 *error_msg = "invalid compressed data before descriptor"; 248 return false; 249 } 250 if (!stream.ReadUInt32(&signature) || 251 signature != kDataDescriptorSignature) { 252 *error_msg = "invalid data descriptor signature"; 253 return false; 254 } 255 if (!stream.ReadUInt32(&zip->crc)) { 256 *error_msg = "invalid crc"; 257 return false; 258 } 259 if (!stream.ReadUInt32(&compressed_size)) { 260 *error_msg = "invalid compressed size"; 261 return false; 262 } 263 if (compressed_size != zip->compressed_data.length()) { 264 *error_msg = "compressed data does not match data descriptor"; 265 return false; 266 } 267 if (!stream.ReadUInt32(&zip->uncompressed_size)) { 268 *error_msg = "invalid compressed size"; 269 return false; 270 } 271 } else { 272 // Just has compressed data. 273 if (!stream.ReadString(&zip->compressed_data, compressed_size)) { 274 *error_msg = "invalid compressed data"; 275 return false; 276 } 277 if (stream.remaining() != 0) { 278 *error_msg = "leftover data after zip entry"; 279 return false; 280 } 281 } 282 return true; 283 } 284 285 // Returns bytes for a valid zip file that just contains this zip entry. 286 std::string ToZip() { 287 // Write zip entry with no data descriptor. 288 DataOutputStream stream; 289 stream.WriteUInt32(kFileHeaderSignature); 290 stream.WriteUInt16(version_needed); 291 stream.WriteUInt16(bit_flag); 292 stream.WriteUInt16(compression_method); 293 stream.WriteUInt16(mod_time); 294 stream.WriteUInt16(mod_date); 295 stream.WriteUInt32(crc); 296 stream.WriteUInt32(compressed_data.length()); 297 stream.WriteUInt32(uncompressed_size); 298 stream.WriteUInt16(name.length()); 299 stream.WriteUInt16(fields.length()); 300 stream.WriteString(name); 301 stream.WriteString(fields); 302 stream.WriteString(compressed_data); 303 uint32 entry_size = stream.buffer().length(); 304 305 // Write central directory. 306 stream.WriteUInt32(kCentralDirSignature); 307 stream.WriteUInt16(0x14); // Version made by. Unused at version 0. 308 stream.WriteUInt16(version_needed); 309 stream.WriteUInt16(bit_flag); 310 stream.WriteUInt16(compression_method); 311 stream.WriteUInt16(mod_time); 312 stream.WriteUInt16(mod_date); 313 stream.WriteUInt32(crc); 314 stream.WriteUInt32(compressed_data.length()); 315 stream.WriteUInt32(uncompressed_size); 316 stream.WriteUInt16(name.length()); 317 stream.WriteUInt16(fields.length()); 318 stream.WriteUInt16(0); // Comment length. 319 stream.WriteUInt16(0); // Disk number where file starts. 320 stream.WriteUInt16(0); // Internal file attr. 321 stream.WriteUInt32(0); // External file attr. 322 stream.WriteUInt32(0); // Offset to file. 323 stream.WriteString(name); 324 stream.WriteString(fields); 325 uint32 cd_size = stream.buffer().length() - entry_size; 326 327 // End of central directory. 328 stream.WriteUInt32(kEndOfCentralDirSignature); 329 stream.WriteUInt16(0); // num of this disk 330 stream.WriteUInt16(0); // disk where cd starts 331 stream.WriteUInt16(1); // number of cds on this disk 332 stream.WriteUInt16(1); // total cds 333 stream.WriteUInt32(cd_size); // size of cd 334 stream.WriteUInt32(entry_size); // offset of cd 335 stream.WriteUInt16(0); // comment len 336 337 return stream.buffer(); 338 } 339 340 static const uint32 kFileHeaderSignature; 341 static const uint32 kDataDescriptorSignature; 342 static const uint32 kCentralDirSignature; 343 static const uint32 kEndOfCentralDirSignature; 344 uint16 version_needed; 345 uint16 bit_flag; 346 uint16 compression_method; 347 uint16 mod_time; 348 uint16 mod_date; 349 uint32 crc; 350 uint32 uncompressed_size; 351 std::string name; 352 std::string fields; 353 std::string compressed_data; 354 }; 355 356 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50; 357 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50; 358 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50; 359 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50; 360 361 Status UnzipEntry(const base::FilePath& unzip_dir, 362 const std::string& bytes) { 363 ZipEntry entry; 364 std::string zip_error_msg; 365 if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg)) 366 return Status(kUnknownError, zip_error_msg); 367 std::string archive = entry.ToZip(); 368 return UnzipArchive(unzip_dir, archive); 369 } 370 371 } // namespace 372 373 Status UnzipSoleFile(const base::FilePath& unzip_dir, 374 const std::string& bytes, 375 base::FilePath* file) { 376 std::string archive_error, entry_error; 377 Status status = UnzipArchive(unzip_dir, bytes); 378 if (status.IsError()) { 379 Status entry_status = UnzipEntry(unzip_dir, bytes); 380 if (entry_status.IsError()) { 381 return Status(kUnknownError, base::StringPrintf( 382 "archive error: (%s), entry error: (%s)", 383 status.message().c_str(), entry_status.message().c_str())); 384 } 385 } 386 387 base::FileEnumerator enumerator(unzip_dir, false /* recursive */, 388 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); 389 base::FilePath first_file = enumerator.Next(); 390 if (first_file.empty()) 391 return Status(kUnknownError, "contained 0 files"); 392 393 base::FilePath second_file = enumerator.Next(); 394 if (!second_file.empty()) 395 return Status(kUnknownError, "contained multiple files"); 396 397 *file = first_file; 398 return Status(kOk); 399 } 400