Home | History | Annotate | Download | only in webdriver
      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", &copy);
     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