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.
5 #include "chrome/test/chromedriver/util.h"
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"
24 std::string GenerateId() {
25 uint64 msb = base::RandUint64();
26 uint64 lsb = base::RandUint64();
27 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb);
32 Status FlattenStringArray(const base::ListValue* src, base::string16* dest) {
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");
44 keys.append(keys_list_part);
52 Status SendKeysOnWindow(
54 const base::ListValue* key_list,
55 bool release_modifiers,
56 int* sticky_modifiers) {
58 Status status = FlattenStringArray(key_list, &keys);
61 std::list<KeyEvent> events;
62 int sticky_modifiers_tmp = *sticky_modifiers;
63 status = ConvertKeysToKeyEvents(
64 keys, release_modifiers, &sticky_modifiers_tmp, &events);
67 status = web_view->DispatchKeyEvents(events);
69 *sticky_modifiers = sticky_modifiers_tmp;
73 bool Base64Decode(const std::string& base64,
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
79 base::RemoveChars(copy, "\n", ©);
80 return base::Base64Decode(copy, bytes);
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");
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");
96 if (!zip::Unzip(archive, unzip_dir))
97 return Status(kUnknownError, "could not unzip archive");
101 // Stream for writing binary data.
102 class DataOutputStream {
104 DataOutputStream() {}
105 ~DataOutputStream() {}
107 void WriteUInt16(uint16 data) {
108 WriteBytes(&data, sizeof(data));
111 void WriteUInt32(uint32 data) {
112 WriteBytes(&data, sizeof(data));
115 void WriteString(const std::string& data) {
116 WriteBytes(data.c_str(), data.length());
119 void WriteBytes(const void* bytes, int size) {
122 size_t next = buffer_.length();
123 buffer_.resize(next + size);
124 memcpy(&buffer_[next], bytes, size);
127 const std::string& buffer() const { return buffer_; }
133 // Stream for reading binary data.
134 class DataInputStream {
136 DataInputStream(const char* data, int size)
137 : data_(data), size_(size), iter_(0) {}
138 ~DataInputStream() {}
140 bool ReadUInt16(uint16* data) {
141 return ReadBytes(data, sizeof(*data));
144 bool ReadUInt32(uint32* data) {
145 return ReadBytes(data, sizeof(*data));
148 bool ReadString(std::string* data, int length) {
151 // Check here to make sure we don't allocate wastefully.
152 if (iter_ + length > size_)
154 data->resize(length);
157 return ReadBytes(&(*data)[0], length);
160 bool ReadBytes(void* bytes, int size) {
161 if (iter_ + size > size_)
163 memcpy(bytes, &data_[iter_], size);
168 int remaining() const { return size_ - iter_; }
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
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());
188 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) {
189 *error_msg = "invalid file header signature";
192 if (!stream.ReadUInt16(&zip->version_needed)) {
193 *error_msg = "invalid version";
196 if (!stream.ReadUInt16(&zip->bit_flag)) {
197 *error_msg = "invalid bit flag";
200 if (!stream.ReadUInt16(&zip->compression_method)) {
201 *error_msg = "invalid compression method";
204 if (!stream.ReadUInt16(&zip->mod_time)) {
205 *error_msg = "invalid file last modified time";
208 if (!stream.ReadUInt16(&zip->mod_date)) {
209 *error_msg = "invalid file last modified date";
212 if (!stream.ReadUInt32(&zip->crc)) {
213 *error_msg = "invalid crc";
216 uint32 compressed_size;
217 if (!stream.ReadUInt32(&compressed_size)) {
218 *error_msg = "invalid compressed size";
221 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
222 *error_msg = "invalid compressed size";
226 if (!stream.ReadUInt16(&name_length)) {
227 *error_msg = "invalid name length";
231 if (!stream.ReadUInt16(&field_length)) {
232 *error_msg = "invalid field length";
235 if (!stream.ReadString(&zip->name, name_length)) {
236 *error_msg = "invalid name";
239 if (!stream.ReadString(&zip->fields, field_length)) {
240 *error_msg = "invalid fields";
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";
249 compressed_size = stream.remaining() - 16;
250 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
251 *error_msg = "invalid compressed data before descriptor";
254 if (!stream.ReadUInt32(&signature) ||
255 signature != kDataDescriptorSignature) {
256 *error_msg = "invalid data descriptor signature";
259 if (!stream.ReadUInt32(&zip->crc)) {
260 *error_msg = "invalid crc";
263 if (!stream.ReadUInt32(&compressed_size)) {
264 *error_msg = "invalid compressed size";
267 if (compressed_size != zip->compressed_data.length()) {
268 *error_msg = "compressed data does not match data descriptor";
271 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
272 *error_msg = "invalid compressed size";
276 // Just has compressed data.
277 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
278 *error_msg = "invalid compressed data";
281 if (stream.remaining() != 0) {
282 *error_msg = "leftover data after zip entry";
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();
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;
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
341 return stream.buffer();
344 static const uint32 kFileHeaderSignature;
345 static const uint32 kDataDescriptorSignature;
346 static const uint32 kCentralDirSignature;
347 static const uint32 kEndOfCentralDirSignature;
348 uint16 version_needed;
350 uint16 compression_method;
354 uint32 uncompressed_size;
357 std::string compressed_data;
360 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50;
361 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50;
362 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50;
363 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50;
365 Status UnzipEntry(const base::FilePath& unzip_dir,
366 const std::string& bytes) {
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);
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()));
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");
397 base::FilePath second_file = enumerator.Next();
398 if (!second_file.empty())
399 return Status(kUnknownError, "contained multiple files");