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/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", &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 (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