Home | History | Annotate | Download | only in chromedriver
      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/key_converter.h"
     22 #include "third_party/zlib/google/zip.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, base::string16* dest) {
     33   base::string16 keys;
     34   for (size_t i = 0; i < src->GetSize(); ++i) {
     35     base::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   base::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", &copy);
     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 (base::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