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");