a4a9c5315d08d4af0a379c7fcff7ad93e9cff9b4
[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/files/file_enumerator.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/format_macros.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/rand_util.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/third_party/icu/icu_utf.h"
18 #include "base/values.h"
19 #include "chrome/test/chromedriver/chrome/chrome.h"
20 #include "chrome/test/chromedriver/chrome/status.h"
21 #include "chrome/test/chromedriver/chrome/ui_events.h"
22 #include "chrome/test/chromedriver/chrome/version.h"
23 #include "chrome/test/chromedriver/chrome/web_view.h"
24 #include "chrome/test/chromedriver/command_listener.h"
25 #include "chrome/test/chromedriver/key_converter.h"
26 #include "chrome/test/chromedriver/session.h"
27 #include "third_party/zlib/google/zip.h"
28
29 std::string GenerateId() {
30   uint64 msb = base::RandUint64();
31   uint64 lsb = base::RandUint64();
32   return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb);
33 }
34
35 namespace {
36
37 Status FlattenStringArray(const base::ListValue* src, base::string16* dest) {
38   base::string16 keys;
39   for (size_t i = 0; i < src->GetSize(); ++i) {
40     base::string16 keys_list_part;
41     if (!src->GetString(i, &keys_list_part))
42       return Status(kUnknownError, "keys should be a string");
43     for (size_t j = 0; j < keys_list_part.size(); ++j) {
44       if (CBU16_IS_SURROGATE(keys_list_part[j])) {
45         return Status(kUnknownError,
46                       "ChromeDriver only supports characters in the BMP");
47       }
48     }
49     keys.append(keys_list_part);
50   }
51   *dest = keys;
52   return Status(kOk);
53 }
54
55 }  // namespace
56
57 Status SendKeysOnWindow(
58     WebView* web_view,
59     const base::ListValue* key_list,
60     bool release_modifiers,
61     int* sticky_modifiers) {
62   base::string16 keys;
63   Status status = FlattenStringArray(key_list, &keys);
64   if (status.IsError())
65     return status;
66   std::list<KeyEvent> events;
67   int sticky_modifiers_tmp = *sticky_modifiers;
68   status = ConvertKeysToKeyEvents(
69       keys, release_modifiers, &sticky_modifiers_tmp, &events);
70   if (status.IsError())
71     return status;
72   status = web_view->DispatchKeyEvents(events);
73   if (status.IsOk())
74     *sticky_modifiers = sticky_modifiers_tmp;
75   return status;
76 }
77
78 bool Base64Decode(const std::string& base64,
79                   std::string* bytes) {
80   std::string copy = base64;
81   // Some WebDriver client base64 encoders follow RFC 1521, which require that
82   // 'encoded lines be no more than 76 characters long'. Just remove any
83   // newlines.
84   base::RemoveChars(copy, "\n", &copy);
85   return base::Base64Decode(copy, bytes);
86 }
87
88 namespace {
89
90 Status UnzipArchive(const base::FilePath& unzip_dir,
91                     const std::string& bytes) {
92   base::ScopedTempDir dir;
93   if (!dir.CreateUniqueTempDir())
94     return Status(kUnknownError, "unable to create temp dir");
95
96   base::FilePath archive = dir.path().AppendASCII("temp.zip");
97   int length = bytes.length();
98   if (base::WriteFile(archive, bytes.c_str(), length) != length)
99     return Status(kUnknownError, "could not write file to temp dir");
100
101   if (!zip::Unzip(archive, unzip_dir))
102     return Status(kUnknownError, "could not unzip archive");
103   return Status(kOk);
104 }
105
106 // Stream for writing binary data.
107 class DataOutputStream {
108  public:
109   DataOutputStream() {}
110   ~DataOutputStream() {}
111
112   void WriteUInt16(uint16 data) {
113     WriteBytes(&data, sizeof(data));
114   }
115
116   void WriteUInt32(uint32 data) {
117     WriteBytes(&data, sizeof(data));
118   }
119
120   void WriteString(const std::string& data) {
121     WriteBytes(data.c_str(), data.length());
122   }
123
124   void WriteBytes(const void* bytes, int size) {
125     if (!size)
126       return;
127     size_t next = buffer_.length();
128     buffer_.resize(next + size);
129     memcpy(&buffer_[next], bytes, size);
130   }
131
132   const std::string& buffer() const { return buffer_; }
133
134  private:
135   std::string buffer_;
136 };
137
138 // Stream for reading binary data.
139 class DataInputStream {
140  public:
141   DataInputStream(const char* data, int size)
142       : data_(data), size_(size), iter_(0) {}
143   ~DataInputStream() {}
144
145   bool ReadUInt16(uint16* data) {
146     return ReadBytes(data, sizeof(*data));
147   }
148
149   bool ReadUInt32(uint32* data) {
150     return ReadBytes(data, sizeof(*data));
151   }
152
153   bool ReadString(std::string* data, int length) {
154     if (length < 0)
155       return false;
156     // Check here to make sure we don't allocate wastefully.
157     if (iter_ + length > size_)
158       return false;
159     data->resize(length);
160     if (length == 0)
161       return true;
162     return ReadBytes(&(*data)[0], length);
163   }
164
165   bool ReadBytes(void* bytes, int size) {
166     if (iter_ + size > size_)
167       return false;
168     memcpy(bytes, &data_[iter_], size);
169     iter_ += size;
170     return true;
171   }
172
173   int remaining() const { return size_ - iter_; }
174
175  private:
176   const char* data_;
177   int size_;
178   int iter_;
179 };
180
181 // A file entry within a zip archive. This may be incomplete and is not
182 // guaranteed to be able to parse all types of zip entries.
183 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip
184 // file format.
185 struct ZipEntry {
186   // The given bytes must contain the whole zip entry and only the entry,
187   // although the entry may include a data descriptor.
188   static bool FromBytes(const std::string& bytes, ZipEntry* zip,
189                         std::string* error_msg) {
190     DataInputStream stream(bytes.c_str(), bytes.length());
191
192     uint32 signature;
193     if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) {
194       *error_msg = "invalid file header signature";
195       return false;
196     }
197     if (!stream.ReadUInt16(&zip->version_needed)) {
198       *error_msg = "invalid version";
199       return false;
200     }
201     if (!stream.ReadUInt16(&zip->bit_flag)) {
202       *error_msg = "invalid bit flag";
203       return false;
204     }
205     if (!stream.ReadUInt16(&zip->compression_method)) {
206       *error_msg = "invalid compression method";
207       return false;
208     }
209     if (!stream.ReadUInt16(&zip->mod_time)) {
210       *error_msg = "invalid file last modified time";
211       return false;
212     }
213     if (!stream.ReadUInt16(&zip->mod_date)) {
214       *error_msg = "invalid file last modified date";
215       return false;
216     }
217     if (!stream.ReadUInt32(&zip->crc)) {
218       *error_msg = "invalid crc";
219       return false;
220     }
221     uint32 compressed_size;
222     if (!stream.ReadUInt32(&compressed_size)) {
223       *error_msg = "invalid compressed size";
224       return false;
225     }
226     if (!stream.ReadUInt32(&zip->uncompressed_size)) {
227       *error_msg = "invalid compressed size";
228       return false;
229     }
230     uint16 name_length;
231     if (!stream.ReadUInt16(&name_length)) {
232       *error_msg = "invalid name length";
233       return false;
234     }
235     uint16 field_length;
236     if (!stream.ReadUInt16(&field_length)) {
237       *error_msg = "invalid field length";
238       return false;
239     }
240     if (!stream.ReadString(&zip->name, name_length)) {
241       *error_msg = "invalid name";
242       return false;
243     }
244     if (!stream.ReadString(&zip->fields, field_length)) {
245       *error_msg = "invalid fields";
246       return false;
247     }
248     if (zip->bit_flag & 0x8) {
249       // Has compressed data and a separate data descriptor.
250       if (stream.remaining() < 16) {
251         *error_msg = "too small for data descriptor";
252         return false;
253       }
254       compressed_size = stream.remaining() - 16;
255       if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
256         *error_msg = "invalid compressed data before descriptor";
257         return false;
258       }
259       if (!stream.ReadUInt32(&signature) ||
260           signature != kDataDescriptorSignature) {
261         *error_msg = "invalid data descriptor signature";
262         return false;
263       }
264       if (!stream.ReadUInt32(&zip->crc)) {
265         *error_msg = "invalid crc";
266         return false;
267       }
268       if (!stream.ReadUInt32(&compressed_size)) {
269         *error_msg = "invalid compressed size";
270         return false;
271       }
272       if (compressed_size != zip->compressed_data.length()) {
273         *error_msg = "compressed data does not match data descriptor";
274         return false;
275       }
276       if (!stream.ReadUInt32(&zip->uncompressed_size)) {
277         *error_msg = "invalid compressed size";
278         return false;
279       }
280     } else {
281       // Just has compressed data.
282       if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
283         *error_msg = "invalid compressed data";
284         return false;
285       }
286       if (stream.remaining() != 0) {
287         *error_msg = "leftover data after zip entry";
288         return false;
289       }
290     }
291     return true;
292   }
293
294   // Returns bytes for a valid zip file that just contains this zip entry.
295   std::string ToZip() {
296     // Write zip entry with no data descriptor.
297     DataOutputStream stream;
298     stream.WriteUInt32(kFileHeaderSignature);
299     stream.WriteUInt16(version_needed);
300     stream.WriteUInt16(bit_flag);
301     stream.WriteUInt16(compression_method);
302     stream.WriteUInt16(mod_time);
303     stream.WriteUInt16(mod_date);
304     stream.WriteUInt32(crc);
305     stream.WriteUInt32(compressed_data.length());
306     stream.WriteUInt32(uncompressed_size);
307     stream.WriteUInt16(name.length());
308     stream.WriteUInt16(fields.length());
309     stream.WriteString(name);
310     stream.WriteString(fields);
311     stream.WriteString(compressed_data);
312     uint32 entry_size = stream.buffer().length();
313
314     // Write central directory.
315     stream.WriteUInt32(kCentralDirSignature);
316     stream.WriteUInt16(0x14);  // Version made by. Unused at version 0.
317     stream.WriteUInt16(version_needed);
318     stream.WriteUInt16(bit_flag);
319     stream.WriteUInt16(compression_method);
320     stream.WriteUInt16(mod_time);
321     stream.WriteUInt16(mod_date);
322     stream.WriteUInt32(crc);
323     stream.WriteUInt32(compressed_data.length());
324     stream.WriteUInt32(uncompressed_size);
325     stream.WriteUInt16(name.length());
326     stream.WriteUInt16(fields.length());
327     stream.WriteUInt16(0);  // Comment length.
328     stream.WriteUInt16(0);  // Disk number where file starts.
329     stream.WriteUInt16(0);  // Internal file attr.
330     stream.WriteUInt32(0);  // External file attr.
331     stream.WriteUInt32(0);  // Offset to file.
332     stream.WriteString(name);
333     stream.WriteString(fields);
334     uint32 cd_size = stream.buffer().length() - entry_size;
335
336     // End of central directory.
337     stream.WriteUInt32(kEndOfCentralDirSignature);
338     stream.WriteUInt16(0);  // num of this disk
339     stream.WriteUInt16(0);  // disk where cd starts
340     stream.WriteUInt16(1);  // number of cds on this disk
341     stream.WriteUInt16(1);  // total cds
342     stream.WriteUInt32(cd_size);  // size of cd
343     stream.WriteUInt32(entry_size);  // offset of cd
344     stream.WriteUInt16(0);  // comment len
345
346     return stream.buffer();
347   }
348
349   static const uint32 kFileHeaderSignature;
350   static const uint32 kDataDescriptorSignature;
351   static const uint32 kCentralDirSignature;
352   static const uint32 kEndOfCentralDirSignature;
353   uint16 version_needed;
354   uint16 bit_flag;
355   uint16 compression_method;
356   uint16 mod_time;
357   uint16 mod_date;
358   uint32 crc;
359   uint32 uncompressed_size;
360   std::string name;
361   std::string fields;
362   std::string compressed_data;
363 };
364
365 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50;
366 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50;
367 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50;
368 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50;
369
370 Status UnzipEntry(const base::FilePath& unzip_dir,
371                   const std::string& bytes) {
372   ZipEntry entry;
373   std::string zip_error_msg;
374   if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg))
375     return Status(kUnknownError, zip_error_msg);
376   std::string archive = entry.ToZip();
377   return UnzipArchive(unzip_dir, archive);
378 }
379
380 }  // namespace
381
382 Status UnzipSoleFile(const base::FilePath& unzip_dir,
383                      const std::string& bytes,
384                      base::FilePath* file) {
385   std::string archive_error, entry_error;
386   Status status = UnzipArchive(unzip_dir, bytes);
387   if (status.IsError()) {
388     Status entry_status = UnzipEntry(unzip_dir, bytes);
389     if (entry_status.IsError()) {
390       return Status(kUnknownError, base::StringPrintf(
391           "archive error: (%s), entry error: (%s)",
392           status.message().c_str(), entry_status.message().c_str()));
393     }
394   }
395
396   base::FileEnumerator enumerator(unzip_dir, false /* recursive */,
397       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
398   base::FilePath first_file = enumerator.Next();
399   if (first_file.empty())
400     return Status(kUnknownError, "contained 0 files");
401
402   base::FilePath second_file = enumerator.Next();
403   if (!second_file.empty())
404     return Status(kUnknownError, "contained multiple files");
405
406   *file = first_file;
407   return Status(kOk);
408 }
409
410 Status NotifyCommandListenersBeforeCommand(Session* session,
411                                            const std::string& command_name) {
412   for (ScopedVector<CommandListener>::const_iterator it =
413        session->command_listeners.begin();
414        it != session->command_listeners.end();
415        ++it) {
416     Status status = (*it)->BeforeCommand(command_name);
417     if (status.IsError()) {
418       // Do not continue if an error is encountered. Mark session for deletion,
419       // quit Chrome if necessary, and return a detailed error.
420       if (!session->quit) {
421         session->quit = true;
422         std::string message = base::StringPrintf("session deleted because "
423             "error encountered when notifying listeners of '%s' command",
424             command_name.c_str());
425         if (session->chrome && !session->detach) {
426           Status quit_status = session->chrome->Quit();
427           if (quit_status.IsError())
428             message += ", but failed to kill browser:" + quit_status.message();
429         }
430         status = Status(kUnknownError, message, status);
431       }
432       if (session->chrome) {
433         const BrowserInfo* browser_info = session->chrome->GetBrowserInfo();
434         status.AddDetails("Session info: " + browser_info->browser_name + "=" +
435                           browser_info->browser_version);
436       }
437       return status;
438     }
439   }
440   return Status(kOk);
441 }