Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1905)

Side by Side Diff: chrome/test/webdriver/webdriver_util.cc

Issue 23526047: Delete old chromedriver code, and remove mongoose webserver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/test/webdriver/webdriver_util.h ('k') | chrome/test/webdriver/webdriver_util_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/webdriver/webdriver_util.h"
6
7 #include "base/base64.h"
8 #include "base/basictypes.h"
9 #include "base/file_util.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/format_macros.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/rand_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/third_party/icu/icu_utf.h"
22 #include "chrome/common/automation_id.h"
23 #include "chrome/test/automation/automation_json_requests.h"
24 #include "third_party/zlib/google/zip.h"
25
26 using base::DictionaryValue;
27 using base::ListValue;
28 using base::Value;
29
30 namespace webdriver {
31
32 SkipParsing* kSkipParsing = NULL;
33
34 std::string GenerateRandomID() {
35 uint64 msb = base::RandUint64();
36 uint64 lsb = base::RandUint64();
37 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb);
38 }
39
40 bool Base64Decode(const std::string& base64,
41 std::string* bytes) {
42 std::string copy = base64;
43 // Some WebDriver client base64 encoders follow RFC 1521, which require that
44 // 'encoded lines be no more than 76 characters long'. Just remove any
45 // newlines.
46 RemoveChars(copy, "\n", &copy);
47 return base::Base64Decode(copy, bytes);
48 }
49
50 namespace {
51
52 bool UnzipArchive(const base::FilePath& unzip_dir,
53 const std::string& bytes,
54 std::string* error_msg) {
55 base::ScopedTempDir dir;
56 if (!dir.CreateUniqueTempDir()) {
57 *error_msg = "Unable to create temp dir";
58 return false;
59 }
60 base::FilePath archive = dir.path().AppendASCII("temp.zip");
61 int length = bytes.length();
62 if (file_util::WriteFile(archive, bytes.c_str(), length) != length) {
63 *error_msg = "Could not write file to temp dir";
64 return false;
65 }
66 if (!zip::Unzip(archive, unzip_dir)) {
67 *error_msg = "Could not unzip archive";
68 return false;
69 }
70 return true;
71 }
72
73 } // namespace
74
75 bool Base64DecodeAndUnzip(const base::FilePath& unzip_dir,
76 const std::string& base64,
77 std::string* error_msg) {
78 std::string zip_data;
79 if (!Base64Decode(base64, &zip_data)) {
80 *error_msg = "Could not decode base64 zip data";
81 return false;
82 }
83 return UnzipArchive(unzip_dir, zip_data, error_msg);
84 }
85
86 namespace {
87
88 // Stream for writing binary data.
89 class DataOutputStream {
90 public:
91 DataOutputStream() {}
92 ~DataOutputStream() {}
93
94 void WriteUInt16(uint16 data) {
95 WriteBytes(&data, sizeof(data));
96 }
97
98 void WriteUInt32(uint32 data) {
99 WriteBytes(&data, sizeof(data));
100 }
101
102 void WriteString(const std::string& data) {
103 WriteBytes(data.c_str(), data.length());
104 }
105
106 void WriteBytes(const void* bytes, int size) {
107 size_t next = buffer_.length();
108 buffer_.resize(next + size);
109 memcpy(&buffer_[next], bytes, size);
110 }
111
112 const std::string& buffer() const { return buffer_; }
113
114 private:
115 std::string buffer_;
116 };
117
118 // Stream for reading binary data.
119 class DataInputStream {
120 public:
121 DataInputStream(const char* data, int size)
122 : data_(data), size_(size), iter_(0) {}
123 ~DataInputStream() {}
124
125 bool ReadUInt16(uint16* data) {
126 return ReadBytes(data, sizeof(*data));
127 }
128
129 bool ReadUInt32(uint32* data) {
130 return ReadBytes(data, sizeof(*data));
131 }
132
133 bool ReadString(std::string* data, int length) {
134 if (length < 0)
135 return false;
136 // Check here to make sure we don't allocate wastefully.
137 if (iter_ + length > size_)
138 return false;
139 data->resize(length);
140 return ReadBytes(&(*data)[0], length);
141 }
142
143 bool ReadBytes(void* bytes, int size) {
144 if (iter_ + size > size_)
145 return false;
146 memcpy(bytes, &data_[iter_], size);
147 iter_ += size;
148 return true;
149 }
150
151 int remaining() const { return size_ - iter_; }
152
153 private:
154 const char* data_;
155 int size_;
156 int iter_;
157 };
158
159 // A file entry within a zip archive. This may be incomplete and is not
160 // guaranteed to be able to parse all types of zip entries.
161 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip
162 // file format.
163 struct ZipEntry {
164 // The given bytes must contain the whole zip entry and only the entry,
165 // although the entry may include a data descriptor.
166 static bool FromBytes(const std::string& bytes, ZipEntry* zip,
167 std::string* error_msg) {
168 DataInputStream stream(bytes.c_str(), bytes.length());
169
170 uint32 signature;
171 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) {
172 *error_msg = "Invalid file header signature";
173 return false;
174 }
175 if (!stream.ReadUInt16(&zip->version_needed)) {
176 *error_msg = "Invalid version";
177 return false;
178 }
179 if (!stream.ReadUInt16(&zip->bit_flag)) {
180 *error_msg = "Invalid bit flag";
181 return false;
182 }
183 if (!stream.ReadUInt16(&zip->compression_method)) {
184 *error_msg = "Invalid compression method";
185 return false;
186 }
187 if (!stream.ReadUInt16(&zip->mod_time)) {
188 *error_msg = "Invalid file last modified time";
189 return false;
190 }
191 if (!stream.ReadUInt16(&zip->mod_date)) {
192 *error_msg = "Invalid file last modified date";
193 return false;
194 }
195 if (!stream.ReadUInt32(&zip->crc)) {
196 *error_msg = "Invalid crc";
197 return false;
198 }
199 uint32 compressed_size;
200 if (!stream.ReadUInt32(&compressed_size)) {
201 *error_msg = "Invalid compressed size";
202 return false;
203 }
204 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
205 *error_msg = "Invalid compressed size";
206 return false;
207 }
208 uint16 name_length;
209 if (!stream.ReadUInt16(&name_length)) {
210 *error_msg = "Invalid name length";
211 return false;
212 }
213 uint16 field_length;
214 if (!stream.ReadUInt16(&field_length)) {
215 *error_msg = "Invalid field length";
216 return false;
217 }
218 if (!stream.ReadString(&zip->name, name_length)) {
219 *error_msg = "Invalid name";
220 return false;
221 }
222 if (!stream.ReadString(&zip->fields, field_length)) {
223 *error_msg = "Invalid fields";
224 return false;
225 }
226 if (zip->bit_flag & 0x8) {
227 // Has compressed data and a separate data descriptor.
228 if (stream.remaining() < 16) {
229 *error_msg = "Too small for data descriptor";
230 return false;
231 }
232 compressed_size = stream.remaining() - 16;
233 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
234 *error_msg = "Invalid compressed data before descriptor";
235 return false;
236 }
237 if (!stream.ReadUInt32(&signature) ||
238 signature != kDataDescriptorSignature) {
239 *error_msg = "Invalid data descriptor signature";
240 return false;
241 }
242 if (!stream.ReadUInt32(&zip->crc)) {
243 *error_msg = "Invalid crc";
244 return false;
245 }
246 if (!stream.ReadUInt32(&compressed_size)) {
247 *error_msg = "Invalid compressed size";
248 return false;
249 }
250 if (compressed_size != zip->compressed_data.length()) {
251 *error_msg = "Compressed data does not match data descriptor";
252 return false;
253 }
254 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
255 *error_msg = "Invalid compressed size";
256 return false;
257 }
258 } else {
259 // Just has compressed data.
260 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
261 *error_msg = "Invalid compressed data";
262 return false;
263 }
264 if (stream.remaining() != 0) {
265 *error_msg = "Leftover data after zip entry";
266 return false;
267 }
268 }
269 return true;
270 }
271
272 // Returns bytes for a valid zip file that just contains this zip entry.
273 std::string ToZip() {
274 // Write zip entry with no data descriptor.
275 DataOutputStream stream;
276 stream.WriteUInt32(kFileHeaderSignature);
277 stream.WriteUInt16(version_needed);
278 stream.WriteUInt16(bit_flag);
279 stream.WriteUInt16(compression_method);
280 stream.WriteUInt16(mod_time);
281 stream.WriteUInt16(mod_date);
282 stream.WriteUInt32(crc);
283 stream.WriteUInt32(compressed_data.length());
284 stream.WriteUInt32(uncompressed_size);
285 stream.WriteUInt16(name.length());
286 stream.WriteUInt16(fields.length());
287 stream.WriteString(name);
288 stream.WriteString(fields);
289 stream.WriteString(compressed_data);
290 uint32 entry_size = stream.buffer().length();
291
292 // Write central directory.
293 stream.WriteUInt32(kCentralDirSignature);
294 stream.WriteUInt16(0x14); // Version made by. Unused at version 0.
295 stream.WriteUInt16(version_needed);
296 stream.WriteUInt16(bit_flag);
297 stream.WriteUInt16(compression_method);
298 stream.WriteUInt16(mod_time);
299 stream.WriteUInt16(mod_date);
300 stream.WriteUInt32(crc);
301 stream.WriteUInt32(compressed_data.length());
302 stream.WriteUInt32(uncompressed_size);
303 stream.WriteUInt16(name.length());
304 stream.WriteUInt16(fields.length());
305 stream.WriteUInt16(0); // Comment length.
306 stream.WriteUInt16(0); // Disk number where file starts.
307 stream.WriteUInt16(0); // Internal file attr.
308 stream.WriteUInt32(0); // External file attr.
309 stream.WriteUInt32(0); // Offset to file.
310 stream.WriteString(name);
311 stream.WriteString(fields);
312 uint32 cd_size = stream.buffer().length() - entry_size;
313
314 // End of central directory.
315 stream.WriteUInt32(kEndOfCentralDirSignature);
316 stream.WriteUInt16(0); // num of this disk
317 stream.WriteUInt16(0); // disk where cd starts
318 stream.WriteUInt16(1); // number of cds on this disk
319 stream.WriteUInt16(1); // total cds
320 stream.WriteUInt32(cd_size); // size of cd
321 stream.WriteUInt32(entry_size); // offset of cd
322 stream.WriteUInt16(0); // comment len
323
324 return stream.buffer();
325 }
326
327 static const uint32 kFileHeaderSignature;
328 static const uint32 kDataDescriptorSignature;
329 static const uint32 kCentralDirSignature;
330 static const uint32 kEndOfCentralDirSignature;
331 uint16 version_needed;
332 uint16 bit_flag;
333 uint16 compression_method;
334 uint16 mod_time;
335 uint16 mod_date;
336 uint32 crc;
337 uint32 uncompressed_size;
338 std::string name;
339 std::string fields;
340 std::string compressed_data;
341 };
342
343 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50;
344 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50;
345 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50;
346 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50;
347
348 bool UnzipEntry(const base::FilePath& unzip_dir,
349 const std::string& bytes,
350 std::string* error_msg) {
351 ZipEntry entry;
352 std::string zip_error_msg;
353 if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg)) {
354 *error_msg = "Error while reading zip entry: " + zip_error_msg;
355 return false;
356 }
357 std::string archive = entry.ToZip();
358 return UnzipArchive(unzip_dir, archive, error_msg);
359 }
360
361 } // namespace
362
363 bool UnzipSoleFile(const base::FilePath& unzip_dir,
364 const std::string& bytes,
365 base::FilePath* file,
366 std::string* error_msg) {
367 std::string archive_error, entry_error;
368 if (!UnzipArchive(unzip_dir, bytes, &archive_error) &&
369 !UnzipEntry(unzip_dir, bytes, &entry_error)) {
370 *error_msg = base::StringPrintf(
371 "Failed to unzip file: Archive error: (%s) Entry error: (%s)",
372 archive_error.c_str(), entry_error.c_str());
373 return false;
374 }
375
376 base::FileEnumerator enumerator(unzip_dir, false /* recursive */,
377 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
378 base::FilePath first_file = enumerator.Next();
379 if (first_file.empty()) {
380 *error_msg = "Zip contained 0 files";
381 return false;
382 }
383 base::FilePath second_file = enumerator.Next();
384 if (!second_file.empty()) {
385 *error_msg = "Zip contained multiple files";
386 return false;
387 }
388 *file = first_file;
389 return true;
390 }
391
392 std::string JsonStringify(const Value* value) {
393 std::string json;
394 base::JSONWriter::Write(value, &json);
395 return json;
396 }
397
398 namespace {
399
400 // Truncates the given string to 100 characters, adding an ellipsis if
401 // truncation was necessary.
402 void TruncateString(std::string* data) {
403 const size_t kMaxLength = 100;
404 if (data->length() > kMaxLength) {
405 data->resize(kMaxLength);
406 data->replace(kMaxLength - 3, 3, "...");
407 }
408 }
409
410 // Truncates all strings contained in the given value.
411 void TruncateContainedStrings(Value* value) {
412 ListValue* list = NULL;
413 DictionaryValue* dict = NULL;
414 if (value->GetAsDictionary(&dict)) {
415 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
416 std::string data;
417 if (it.value().GetAsString(&data)) {
418 TruncateString(&data);
419 dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data));
420 } else {
421 Value* child = NULL;
422 dict->GetWithoutPathExpansion(it.key(), &child);
423 TruncateContainedStrings(child);
424 }
425 }
426 } else if (value->GetAsList(&list)) {
427 for (size_t i = 0; i < list->GetSize(); ++i) {
428 Value* child;
429 if (!list->Get(i, &child))
430 continue;
431 std::string data;
432 if (child->GetAsString(&data)) {
433 TruncateString(&data);
434 list->Set(i, new base::StringValue(data));
435 } else {
436 TruncateContainedStrings(child);
437 }
438 }
439 }
440 }
441
442 } // namespace
443
444 std::string JsonStringifyForDisplay(const Value* value) {
445 scoped_ptr<Value> copy;
446 if (value->IsType(Value::TYPE_STRING)) {
447 std::string data;
448 value->GetAsString(&data);
449 TruncateString(&data);
450 copy.reset(new base::StringValue(data));
451 } else {
452 copy.reset(value->DeepCopy());
453 TruncateContainedStrings(copy.get());
454 }
455 std::string json;
456 base::JSONWriter::WriteWithOptions(copy.get(),
457 base::JSONWriter::OPTIONS_PRETTY_PRINT,
458 &json);
459 return json;
460 }
461
462 const char* GetJsonTypeName(Value::Type type) {
463 switch (type) {
464 case Value::TYPE_NULL:
465 return "null";
466 case Value::TYPE_BOOLEAN:
467 return "boolean";
468 case Value::TYPE_INTEGER:
469 return "integer";
470 case Value::TYPE_DOUBLE:
471 return "double";
472 case Value::TYPE_STRING:
473 return "string";
474 case Value::TYPE_BINARY:
475 return "binary";
476 case Value::TYPE_DICTIONARY:
477 return "dictionary";
478 case Value::TYPE_LIST:
479 return "list";
480 }
481 return "unknown";
482 }
483
484 std::string AutomationIdToString(const AutomationId& id) {
485 return base::StringPrintf("%d-%s", id.type(), id.id().c_str());
486 }
487
488 bool StringToAutomationId(const std::string& string_id, AutomationId* id) {
489 std::vector<std::string> split_id;
490 base::SplitString(string_id, '-', &split_id);
491 if (split_id.size() != 2)
492 return false;
493 int type;
494 if (!base::StringToInt(split_id[0], &type))
495 return false;
496 *id = AutomationId(static_cast<AutomationId::Type>(type), split_id[1]);
497 return true;
498 }
499
500 std::string WebViewIdToString(const WebViewId& view_id) {
501 return base::StringPrintf(
502 "%s%s",
503 view_id.old_style() ? "t" : "f",
504 AutomationIdToString(view_id.GetId()).c_str());
505 }
506
507 bool StringToWebViewId(const std::string& string_id, WebViewId* view_id) {
508 if (string_id.empty() || (string_id[0] != 'f' && string_id[0] != 't'))
509 return false;
510 bool old_style = string_id[0] == 't';
511 AutomationId id;
512 if (!StringToAutomationId(string_id.substr(1), &id))
513 return false;
514
515 if (old_style) {
516 int tab_id;
517 if (!base::StringToInt(id.id(), &tab_id))
518 return false;
519 *view_id = WebViewId::ForOldStyleTab(tab_id);
520 } else {
521 *view_id = WebViewId::ForView(id);
522 }
523 return true;
524 }
525
526 Error* FlattenStringArray(const ListValue* src, string16* dest) {
527 string16 keys;
528 for (size_t i = 0; i < src->GetSize(); ++i) {
529 string16 keys_list_part;
530 src->GetString(i, &keys_list_part);
531 for (size_t j = 0; j < keys_list_part.size(); ++j) {
532 if (CBU16_IS_SURROGATE(keys_list_part[j])) {
533 return new Error(kBadRequest,
534 "ChromeDriver only supports characters in the BMP");
535 }
536 }
537 keys.append(keys_list_part);
538 }
539 *dest = keys;
540 return NULL;
541 }
542
543 ValueParser::ValueParser() { }
544
545 ValueParser::~ValueParser() { }
546
547 } // namespace webdriver
548
549 bool ValueConversionTraits<webdriver::SkipParsing>::SetFromValue(
550 const Value* value, const webdriver::SkipParsing* t) {
551 return true;
552 }
553
554 bool ValueConversionTraits<webdriver::SkipParsing>::CanConvert(
555 const Value* value) {
556 return true;
557 }
OLDNEW
« no previous file with comments | « chrome/test/webdriver/webdriver_util.h ('k') | chrome/test/webdriver/webdriver_util_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698