Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / util.cc
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, 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 (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 }