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 <stddef.h>
8 #include <stdint.h>
9 
10 #include "base/base64.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/format_macros.h"
15 #include "base/rand_util.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/third_party/icu/icu_utf.h"
20 #include "base/values.h"
21 #include "chrome/test/chromedriver/chrome/browser_info.h"
22 #include "chrome/test/chromedriver/chrome/chrome.h"
23 #include "chrome/test/chromedriver/chrome/status.h"
24 #include "chrome/test/chromedriver/chrome/ui_events.h"
25 #include "chrome/test/chromedriver/chrome/web_view.h"
26 #include "chrome/test/chromedriver/command_listener.h"
27 #include "chrome/test/chromedriver/constants/version.h"
28 #include "chrome/test/chromedriver/key_converter.h"
29 #include "chrome/test/chromedriver/session.h"
30 #include "third_party/zlib/google/zip.h"
31 
32 const char kWindowHandlePrefix[] = "CDwindow-";
33 
GenerateId()34 std::string GenerateId() {
35   uint64_t msb = base::RandUint64();
36   uint64_t lsb = base::RandUint64();
37   return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb);
38 }
39 
40 namespace {
41 const double kCentimetersPerInch = 2.54;
42 
FlattenStringArray(const base::ListValue * src,base::string16 * dest)43 Status FlattenStringArray(const base::ListValue* src, base::string16* dest) {
44   base::string16 keys;
45   for (size_t i = 0; i < src->GetSize(); ++i) {
46     base::string16 keys_list_part;
47     if (!src->GetString(i, &keys_list_part))
48       return Status(kUnknownError, "keys should be a string");
49     for (size_t j = 0; j < keys_list_part.size(); ++j) {
50       if (CBU16_IS_SURROGATE(keys_list_part[j])) {
51         return Status(
52             kUnknownError,
53             base::StringPrintf("%s only supports characters in the BMP",
54                                kChromeDriverProductShortName));
55       }
56     }
57     keys.append(keys_list_part);
58   }
59   *dest = keys;
60   return Status(kOk);
61 }
62 
63 }  // namespace
64 
SendKeysOnWindow(WebView * web_view,const base::ListValue * key_list,bool release_modifiers,int * sticky_modifiers)65 Status SendKeysOnWindow(
66     WebView* web_view,
67     const base::ListValue* key_list,
68     bool release_modifiers,
69     int* sticky_modifiers) {
70   base::string16 keys;
71   Status status = FlattenStringArray(key_list, &keys);
72   if (status.IsError())
73     return status;
74   std::vector<KeyEvent> events;
75   int sticky_modifiers_tmp = *sticky_modifiers;
76   status = ConvertKeysToKeyEvents(
77       keys, release_modifiers, &sticky_modifiers_tmp, &events);
78   if (status.IsError())
79     return status;
80   status = web_view->DispatchKeyEvents(events, false);
81   if (status.IsOk())
82     *sticky_modifiers = sticky_modifiers_tmp;
83   return status;
84 }
85 
Base64Decode(const std::string & base64,std::string * bytes)86 bool Base64Decode(const std::string& base64,
87                   std::string* bytes) {
88   std::string copy = base64;
89   // Some WebDriver client base64 encoders follow RFC 1521, which require that
90   // 'encoded lines be no more than 76 characters long'. Just remove any
91   // newlines.
92   base::RemoveChars(copy, "\n", &copy);
93   return base::Base64Decode(copy, bytes);
94 }
95 
96 namespace {
97 
UnzipArchive(const base::FilePath & unzip_dir,const std::string & bytes)98 Status UnzipArchive(const base::FilePath& unzip_dir,
99                     const std::string& bytes) {
100   base::ScopedTempDir dir;
101   if (!dir.CreateUniqueTempDir())
102     return Status(kUnknownError, "unable to create temp dir");
103 
104   base::FilePath archive = dir.GetPath().AppendASCII("temp.zip");
105   int length = bytes.length();
106   if (base::WriteFile(archive, bytes.c_str(), length) != length)
107     return Status(kUnknownError, "could not write file to temp dir");
108 
109   if (!zip::Unzip(archive, unzip_dir))
110     return Status(kUnknownError, "could not unzip archive");
111   return Status(kOk);
112 }
113 
114 // Stream for writing binary data.
115 class DataOutputStream {
116  public:
DataOutputStream()117   DataOutputStream() {}
~DataOutputStream()118   ~DataOutputStream() {}
119 
WriteUInt16(uint16_t data)120   void WriteUInt16(uint16_t data) { WriteBytes(&data, sizeof(data)); }
121 
WriteUInt32(uint32_t data)122   void WriteUInt32(uint32_t data) { WriteBytes(&data, sizeof(data)); }
123 
WriteString(const std::string & data)124   void WriteString(const std::string& data) {
125     WriteBytes(data.c_str(), data.length());
126   }
127 
WriteBytes(const void * bytes,int size)128   void WriteBytes(const void* bytes, int size) {
129     if (!size)
130       return;
131     size_t next = buffer_.length();
132     buffer_.resize(next + size);
133     memcpy(&buffer_[next], bytes, size);
134   }
135 
buffer() const136   const std::string& buffer() const { return buffer_; }
137 
138  private:
139   std::string buffer_;
140 };
141 
142 // Stream for reading binary data.
143 class DataInputStream {
144  public:
DataInputStream(const char * data,int size)145   DataInputStream(const char* data, int size)
146       : data_(data), size_(size), iter_(0) {}
~DataInputStream()147   ~DataInputStream() {}
148 
ReadUInt16(uint16_t * data)149   bool ReadUInt16(uint16_t* data) { return ReadBytes(data, sizeof(*data)); }
150 
ReadUInt32(uint32_t * data)151   bool ReadUInt32(uint32_t* data) { return ReadBytes(data, sizeof(*data)); }
152 
ReadString(std::string * data,int length)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 
ReadBytes(void * bytes,int size)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 
remaining() const173   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.
FromBytes__anonafd7ad0c0211::ZipEntry188   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_t 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_t 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_t name_length;
231     if (!stream.ReadUInt16(&name_length)) {
232       *error_msg = "invalid name length";
233       return false;
234     }
235     uint16_t 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.
ToZip__anonafd7ad0c0211::ZipEntry295   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_t 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_t 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_t kFileHeaderSignature;
350   static const uint32_t kDataDescriptorSignature;
351   static const uint32_t kCentralDirSignature;
352   static const uint32_t kEndOfCentralDirSignature;
353   uint16_t version_needed;
354   uint16_t bit_flag;
355   uint16_t compression_method;
356   uint16_t mod_time;
357   uint16_t mod_date;
358   uint32_t crc;
359   uint32_t uncompressed_size;
360   std::string name;
361   std::string fields;
362   std::string compressed_data;
363 };
364 
365 const uint32_t ZipEntry::kFileHeaderSignature = 0x04034b50;
366 const uint32_t ZipEntry::kDataDescriptorSignature = 0x08074b50;
367 const uint32_t ZipEntry::kCentralDirSignature = 0x02014b50;
368 const uint32_t ZipEntry::kEndOfCentralDirSignature = 0x06054b50;
369 
UnzipEntry(const base::FilePath & unzip_dir,const std::string & bytes)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 
UnzipSoleFile(const base::FilePath & unzip_dir,const std::string & bytes,base::FilePath * file)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 
NotifyCommandListenersBeforeCommand(Session * session,const std::string & command_name)410 Status NotifyCommandListenersBeforeCommand(Session* session,
411                                            const std::string& command_name) {
412   for (const auto& listener : session->command_listeners) {
413     Status status = listener->BeforeCommand(command_name);
414     if (status.IsError()) {
415       // Do not continue if an error is encountered. Mark session for deletion,
416       // quit Chrome if necessary, and return a detailed error.
417       if (!session->quit) {
418         session->quit = true;
419         std::string message = base::StringPrintf("session deleted because "
420             "error encountered when notifying listeners of '%s' command",
421             command_name.c_str());
422         if (session->chrome && !session->detach) {
423           Status quit_status = session->chrome->Quit();
424           if (quit_status.IsError())
425             message += ", but failed to kill browser:" + quit_status.message();
426         }
427         status = Status(kUnknownError, message, status);
428       }
429       if (session->chrome) {
430         const BrowserInfo* browser_info = session->chrome->GetBrowserInfo();
431         status.AddDetails("Session info: " + browser_info->browser_name + "=" +
432                           browser_info->browser_version);
433       }
434       return status;
435     }
436   }
437   return Status(kOk);
438 }
439 
ConvertCentimeterToInch(double centimeter)440 double ConvertCentimeterToInch(double centimeter) {
441   return centimeter / kCentimetersPerInch;
442 }
443 
444 namespace {
445 
446 template <typename T>
GetOptionalValue(const base::DictionaryValue * dict,base::StringPiece path,T * out_value,bool * has_value,bool (base::Value::* getter)(T *)const)447 bool GetOptionalValue(const base::DictionaryValue* dict,
448                       base::StringPiece path,
449                       T* out_value,
450                       bool* has_value,
451                       bool (base::Value::*getter)(T*) const) {
452   if (has_value != nullptr)
453     *has_value = false;
454   const base::Value* value;
455   if (!dict->Get(path, &value))
456     return true;
457   if ((value->*getter)(out_value)) {
458     if (has_value != nullptr)
459       *has_value = true;
460     return true;
461   }
462   return false;
463 }
464 
465 }  // namespace
466 
GetOptionalBool(const base::DictionaryValue * dict,base::StringPiece path,bool * out_value,bool * has_value)467 bool GetOptionalBool(const base::DictionaryValue* dict,
468                      base::StringPiece path,
469                      bool* out_value,
470                      bool* has_value) {
471   return GetOptionalValue(dict, path, out_value, has_value,
472                           &base::Value::GetAsBoolean);
473 }
474 
GetOptionalInt(const base::DictionaryValue * dict,base::StringPiece path,int * out_value,bool * has_value)475 bool GetOptionalInt(const base::DictionaryValue* dict,
476                     base::StringPiece path,
477                     int* out_value,
478                     bool* has_value) {
479   if (GetOptionalValue(dict, path, out_value, has_value,
480                        &base::Value::GetAsInteger)) {
481     return true;
482   }
483   // See if we have a double that contains an int value.
484   double d;
485   if (!dict->GetDouble(path, &d))
486     return false;
487   int i = static_cast<int>(d);
488   if (i == d) {
489     *out_value = i;
490     if (has_value != nullptr)
491       *has_value = true;
492     return true;
493   }
494   return false;
495 }
496 
GetOptionalDouble(const base::DictionaryValue * dict,base::StringPiece path,double * out_value,bool * has_value)497 bool GetOptionalDouble(const base::DictionaryValue* dict,
498                        base::StringPiece path,
499                        double* out_value,
500                        bool* has_value) {
501   // base::Value::GetAsDouble already converts int to double if needed.
502   return GetOptionalValue(dict, path, out_value, has_value,
503                           &base::Value::GetAsDouble);
504 }
505 
GetOptionalString(const base::DictionaryValue * dict,base::StringPiece path,std::string * out_value,bool * has_value)506 bool GetOptionalString(const base::DictionaryValue* dict,
507                        base::StringPiece path,
508                        std::string* out_value,
509                        bool* has_value) {
510   return GetOptionalValue(dict, path, out_value, has_value,
511                           &base::Value::GetAsString);
512 }
513 
GetOptionalDictionary(const base::DictionaryValue * dict,base::StringPiece path,const base::DictionaryValue ** out_value,bool * has_value)514 bool GetOptionalDictionary(const base::DictionaryValue* dict,
515                            base::StringPiece path,
516                            const base::DictionaryValue** out_value,
517                            bool* has_value) {
518   return GetOptionalValue(dict, path, out_value, has_value,
519                           &base::Value::GetAsDictionary);
520 }
521 
GetOptionalList(const base::DictionaryValue * dict,base::StringPiece path,const base::ListValue ** out_value,bool * has_value)522 bool GetOptionalList(const base::DictionaryValue* dict,
523                      base::StringPiece path,
524                      const base::ListValue** out_value,
525                      bool* has_value) {
526   return GetOptionalValue(dict, path, out_value, has_value,
527                           &base::Value::GetAsList);
528 }
529 
GetOptionalSafeInt(const base::DictionaryValue * dict,base::StringPiece path,int64_t * out_value,bool * has_value)530 bool GetOptionalSafeInt(const base::DictionaryValue* dict,
531                         base::StringPiece path,
532                         int64_t* out_value,
533                         bool* has_value) {
534   // Check if we have a normal int, which is always a safe int.
535   int temp_int;
536   bool temp_has_value;
537   if (GetOptionalValue(dict, path, &temp_int, &temp_has_value,
538                        &base::Value::GetAsInteger)) {
539     if (has_value != nullptr)
540       *has_value = temp_has_value;
541     if (temp_has_value)
542       *out_value = temp_int;
543     return true;
544   }
545 
546   // Check if we have a double, which may or may not contain a safe int value.
547   double temp_double;
548   if (!dict->GetDouble(path, &temp_double))
549     return false;
550 
551   // Verify that the value is an integer.
552   int64_t temp_int64 = static_cast<int64_t>(temp_double);
553   if (temp_int64 != temp_double)
554     return false;
555 
556   // Verify that the value is in the range for safe integer.
557   if (temp_int64 >= (1ll << 53) || temp_int64 <= -(1ll << 53))
558     return false;
559 
560   // Got a good value.
561   *out_value = temp_int64;
562   if (has_value != nullptr)
563     *has_value = true;
564   return true;
565 }
566 
SetSafeInt(base::DictionaryValue * dict,const base::StringPiece path,int64_t in_value_64)567 bool SetSafeInt(base::DictionaryValue* dict,
568                 const base::StringPiece path,
569                 int64_t in_value_64) {
570   int int_value = static_cast<int>(in_value_64);
571   if (in_value_64 == int_value)
572     return dict->SetInteger(path, in_value_64);
573   else
574     return dict->SetDouble(path, in_value_64);
575 }
576 
WebViewIdToWindowHandle(const std::string & web_view_id)577 std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
578   return kWindowHandlePrefix + web_view_id;
579 }
580 
WindowHandleToWebViewId(const std::string & window_handle,std::string * web_view_id)581 bool WindowHandleToWebViewId(const std::string& window_handle,
582                              std::string* web_view_id) {
583   if (!base::StartsWith(window_handle, kWindowHandlePrefix,
584                         base::CompareCase::SENSITIVE)) {
585     return false;
586   }
587   *web_view_id = window_handle.substr(sizeof(kWindowHandlePrefix) - 1);
588   return true;
589 }
590