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

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

Issue 9515005: [chromedriver] Add command for uploading a file to a remote ChromeDriver server, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 9 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/test/webdriver/webdriver_util.h" 5 #include "chrome/test/webdriver/webdriver_util.h"
6 6
7 #include "base/base64.h"
7 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/file_util.h"
8 #include "base/format_macros.h" 10 #include "base/format_macros.h"
9 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h" 12 #include "base/json/json_writer.h"
11 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
12 #include "base/rand_util.h" 14 #include "base/rand_util.h"
15 #include "base/scoped_temp_dir.h"
13 #include "base/stringprintf.h" 16 #include "base/stringprintf.h"
14 #include "base/string_number_conversions.h" 17 #include "base/string_number_conversions.h"
15 #include "base/string_split.h" 18 #include "base/string_split.h"
19 #include "base/string_util.h"
16 #include "base/third_party/icu/icu_utf.h" 20 #include "base/third_party/icu/icu_utf.h"
17 #include "chrome/common/automation_id.h" 21 #include "chrome/common/automation_id.h"
22 #include "chrome/common/zip.h"
18 #include "chrome/test/automation/automation_json_requests.h" 23 #include "chrome/test/automation/automation_json_requests.h"
19 24
20 using base::DictionaryValue; 25 using base::DictionaryValue;
21 using base::ListValue; 26 using base::ListValue;
22 using base::Value; 27 using base::Value;
23 28
24 namespace webdriver { 29 namespace webdriver {
25 30
26 SkipParsing* kSkipParsing = NULL; 31 SkipParsing* kSkipParsing = NULL;
27 32
28 std::string GenerateRandomID() { 33 std::string GenerateRandomID() {
29 uint64 msb = base::RandUint64(); 34 uint64 msb = base::RandUint64();
30 uint64 lsb = base::RandUint64(); 35 uint64 lsb = base::RandUint64();
31 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb); 36 return base::StringPrintf("%016" PRIx64 "%016" PRIx64, msb, lsb);
32 } 37 }
33 38
39 bool Base64Decode(const std::string& base64,
40 std::string* bytes) {
41 std::string copy = base64;
42 // Some WebDriver client base64 encoders follow RFC 1521, which require that
43 // 'encoded lines be no more than 76 characters long'. Just remove any
44 // newlines.
45 RemoveChars(copy, "\n", &copy);
46 return base::Base64Decode(copy, bytes);
47 }
48
49 namespace {
50
51 bool UnzipArchive(const FilePath& unzip_dir,
52 const std::string& bytes,
53 std::string* error_msg) {
54 ScopedTempDir dir;
55 if (!dir.CreateUniqueTempDir()) {
56 *error_msg = "Unable to create temp dir";
57 return false;
58 }
59 FilePath archive = dir.path().AppendASCII("temp.zip");
60 int length = bytes.length();
61 if (file_util::WriteFile(archive, bytes.c_str(), length) != length) {
62 *error_msg = "Could not write file to temp dir";
63 return false;
64 }
65 if (!zip::Unzip(archive, unzip_dir)) {
66 *error_msg = "Could not unzip archive";
67 return false;
68 }
69 return true;
70 }
71
72 } // namespace
73
74 bool Base64DecodeAndUnzip(const FilePath& unzip_dir,
75 const std::string& base64,
76 std::string* error_msg) {
77 std::string zip_data;
78 if (!Base64Decode(base64, &zip_data)) {
79 *error_msg = "Could not decode base64 zip data";
80 return false;
81 }
82 return UnzipArchive(unzip_dir, zip_data, error_msg);
83 }
84
85 namespace {
86
87 // Stream for writing binary data.
88 class DataOutputStream {
89 public:
90 DataOutputStream() {}
91 ~DataOutputStream() {}
92
93 void WriteUInt16(uint16 data) {
94 WriteBytes(&data, sizeof(data));
95 }
96
97 void WriteUInt32(uint32 data) {
98 WriteBytes(&data, sizeof(data));
99 }
100
101 void WriteString(const std::string& data) {
102 WriteBytes(data.c_str(), data.length());
103 }
104
105 void WriteBytes(const void* bytes, int size) {
106 size_t next = buffer_.length();
107 buffer_.resize(next + size);
108 memcpy(&buffer_[next], bytes, size);
109 }
110
111 const std::string& buffer() const { return buffer_; }
112
113 private:
114 std::string buffer_;
115 };
116
117 // Stream for reading binary data.
118 class DataInputStream {
119 public:
120 DataInputStream(const char* data, int size)
121 : data_(data), size_(size), iter_(0) {}
122 ~DataInputStream() {}
123
124 bool ReadUInt16(uint16* data) {
125 return ReadBytes(data, sizeof(*data));
126 }
127
128 bool ReadUInt32(uint32* data) {
129 return ReadBytes(data, sizeof(*data));
130 }
131
132 bool ReadString(std::string* data, int length) {
133 if (length < 0)
134 return false;
135 // Check here to make sure we don't allocate wastefully.
136 if (iter_ + length > size_)
137 return false;
138 data->resize(length);
139 return ReadBytes(&(*data)[0], length);
140 }
141
142 bool ReadBytes(void* bytes, int size) {
143 if (iter_ + size > size_)
144 return false;
145 memcpy(bytes, &data_[iter_], size);
146 iter_ += size;
147 return true;
148 }
149
150 int remaining() const { return size_ - iter_; }
151
152 private:
153 const char* data_;
154 int size_;
155 int iter_;
156 };
157
158 // A file entry within a zip archive. This may be incomplete and is not
159 // guaranteed to be able to parse all types of zip entries.
160 // See http://www.pkware.com/documents/casestudies/APPNOTE.TXT for the zip
161 // file format.
162 struct ZipEntry {
163 // The given bytes must contain the whole zip entry and only the entry,
164 // although the entry may include a data descriptor.
165 static bool FromBytes(const std::string& bytes, ZipEntry* zip,
166 std::string* error_msg) {
167 DataInputStream stream(bytes.c_str(), bytes.length());
168
169 uint32 signature;
170 if (!stream.ReadUInt32(&signature) || signature != kFileHeaderSignature) {
171 *error_msg = "Invalid file header signature";
172 return false;
173 }
174 if (!stream.ReadUInt16(&zip->version_needed)) {
175 *error_msg = "Invalid version";
176 return false;
177 }
178 if (!stream.ReadUInt16(&zip->bit_flag)) {
179 *error_msg = "Invalid bit flag";
180 return false;
181 }
182 if (!stream.ReadUInt16(&zip->compression_method)) {
183 *error_msg = "Invalid compression method";
184 return false;
185 }
186 if (!stream.ReadUInt16(&zip->mod_time)) {
187 *error_msg = "Invalid file last modified time";
188 return false;
189 }
190 if (!stream.ReadUInt16(&zip->mod_date)) {
191 *error_msg = "Invalid file last modified date";
192 return false;
193 }
194 if (!stream.ReadUInt32(&zip->crc)) {
195 *error_msg = "Invalid crc";
196 return false;
197 }
198 uint32 compressed_size;
199 if (!stream.ReadUInt32(&compressed_size)) {
200 *error_msg = "Invalid compressed size";
201 return false;
202 }
203 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
204 *error_msg = "Invalid compressed size";
205 return false;
206 }
207 uint16 name_length;
208 if (!stream.ReadUInt16(&name_length)) {
209 *error_msg = "Invalid name length";
210 return false;
211 }
212 uint16 field_length;
213 if (!stream.ReadUInt16(&field_length)) {
214 *error_msg = "Invalid field length";
215 return false;
216 }
217 if (!stream.ReadString(&zip->name, name_length)) {
218 *error_msg = "Invalid name";
219 return false;
220 }
221 if (!stream.ReadString(&zip->fields, field_length)) {
222 *error_msg = "Invalid fields";
223 return false;
224 }
225 if (zip->bit_flag & 0x8) {
226 // Has compressed data and a separate data descriptor.
227 if (stream.remaining() < 16) {
228 *error_msg = "Too small for data descriptor";
229 return false;
230 }
231 compressed_size = stream.remaining() - 16;
232 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
233 *error_msg = "Invalid compressed data before descriptor";
234 return false;
235 }
236 if (!stream.ReadUInt32(&signature) ||
237 signature != kDataDescriptorSignature) {
238 *error_msg = "Invalid data descriptor signature";
239 return false;
240 }
241 if (!stream.ReadUInt32(&zip->crc)) {
242 *error_msg = "Invalid crc";
243 return false;
244 }
245 if (!stream.ReadUInt32(&compressed_size)) {
246 *error_msg = "Invalid compressed size";
247 return false;
248 }
249 if (compressed_size != zip->compressed_data.length()) {
250 *error_msg = "Compressed data does not match data descriptor";
251 return false;
252 }
253 if (!stream.ReadUInt32(&zip->uncompressed_size)) {
254 *error_msg = "Invalid compressed size";
255 return false;
256 }
257 } else {
258 // Just has compressed data.
259 if (!stream.ReadString(&zip->compressed_data, compressed_size)) {
260 *error_msg = "Invalid compressed data";
261 return false;
262 }
263 if (stream.remaining() != 0) {
264 *error_msg = "Leftover data after zip entry";
265 return false;
266 }
267 }
268 return true;
269 }
270
271 // Returns bytes for a valid zip file that just contains this zip entry.
272 std::string ToZip() {
273 // Write zip entry with no data descriptor.
274 DataOutputStream stream;
275 stream.WriteUInt32(kFileHeaderSignature);
276 stream.WriteUInt16(version_needed);
277 stream.WriteUInt16(bit_flag);
278 stream.WriteUInt16(compression_method);
279 stream.WriteUInt16(mod_time);
280 stream.WriteUInt16(mod_date);
281 stream.WriteUInt32(crc);
282 stream.WriteUInt32(compressed_data.length());
283 stream.WriteUInt32(uncompressed_size);
284 stream.WriteUInt16(name.length());
285 stream.WriteUInt16(fields.length());
286 stream.WriteString(name);
287 stream.WriteString(fields);
288 stream.WriteString(compressed_data);
289 uint32 entry_size = stream.buffer().length();
290
291 // Write central directory.
292 stream.WriteUInt32(kCentralDirSignature);
293 stream.WriteUInt16(0x14); // Version made by. Unused at version 0.
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.WriteUInt16(0); // Comment length.
305 stream.WriteUInt16(0); // Disk number where file starts.
306 stream.WriteUInt16(0); // Internal file attr.
307 stream.WriteUInt32(0); // External file attr.
308 stream.WriteUInt32(0); // Offset to file.
309 stream.WriteString(name);
310 stream.WriteString(fields);
311 uint32 cd_size = stream.buffer().length() - entry_size;
312
313 // End of central directory.
314 stream.WriteUInt32(kEndOfCentralDirSignature);
315 stream.WriteUInt16(0); // num of this disk
316 stream.WriteUInt16(0); // disk where cd starts
317 stream.WriteUInt16(1); // number of cds on this disk
318 stream.WriteUInt16(1); // total cds
319 stream.WriteUInt32(cd_size); // size of cd
320 stream.WriteUInt32(entry_size); // offset of cd
321 stream.WriteUInt16(0); // comment len
322
323 return stream.buffer();
324 }
325
326 static const uint32 kFileHeaderSignature;
327 static const uint32 kDataDescriptorSignature;
328 static const uint32 kCentralDirSignature;
329 static const uint32 kEndOfCentralDirSignature;
330 uint16 version_needed;
331 uint16 bit_flag;
332 uint16 compression_method;
333 uint16 mod_time;
334 uint16 mod_date;
335 uint32 crc;
336 uint32 uncompressed_size;
337 std::string name;
338 std::string fields;
339 std::string compressed_data;
340 };
341
342 const uint32 ZipEntry::kFileHeaderSignature = 0x04034b50;
343 const uint32 ZipEntry::kDataDescriptorSignature = 0x08074b50;
344 const uint32 ZipEntry::kCentralDirSignature = 0x02014b50;
345 const uint32 ZipEntry::kEndOfCentralDirSignature = 0x06054b50;
346
347 bool UnzipEntry(const FilePath& unzip_dir,
348 const std::string& bytes,
349 std::string* error_msg) {
350 ZipEntry entry;
351 std::string zip_error_msg;
352 if (!ZipEntry::FromBytes(bytes, &entry, &zip_error_msg)) {
353 *error_msg = "Error while reading zip entry: " + zip_error_msg;
354 return false;
355 }
356 std::string archive = entry.ToZip();
357 return UnzipArchive(unzip_dir, archive, error_msg);
358 }
359
360 } // namespace
361
362 bool UnzipSoleFile(const FilePath& unzip_dir,
363 const std::string& bytes,
364 FilePath* file,
365 std::string* error_msg) {
366 std::string archive_error, entry_error;
367 if (!UnzipArchive(unzip_dir, bytes, &archive_error) &&
368 !UnzipEntry(unzip_dir, bytes, &entry_error)) {
369 *error_msg = base::StringPrintf(
370 "Failed to unzip file: Archive error: (%s) Entry error: (%s)",
371 archive_error.c_str(), entry_error.c_str());
372 return false;
373 }
374
375 file_util::FileEnumerator enumerator(unzip_dir, false /* recursive */,
376 static_cast<file_util::FileEnumerator::FileType>(
377 file_util::FileEnumerator::FILES |
378 file_util::FileEnumerator::DIRECTORIES));
379 FilePath first_file = enumerator.Next();
380 if (first_file.empty()) {
381 *error_msg = "Zip contained 0 files";
382 return false;
383 }
384 FilePath second_file = enumerator.Next();
385 if (!second_file.empty()) {
386 *error_msg = "Zip contained multiple files";
387 return false;
388 }
389 *file = first_file;
390 return true;
391 }
392
34 std::string JsonStringify(const Value* value) { 393 std::string JsonStringify(const Value* value) {
35 std::string json; 394 std::string json;
36 base::JSONWriter::Write(value, false, &json); 395 base::JSONWriter::Write(value, false, &json);
37 return json; 396 return json;
38 } 397 }
39 398
40 namespace { 399 namespace {
41 400
42 // Truncates the given string to 40 characters, adding an ellipsis if 401 // Truncates the given string to 40 characters, adding an ellipsis if
43 // truncation was necessary. 402 // truncation was necessary.
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 548
190 bool ValueConversionTraits<webdriver::SkipParsing>::SetFromValue( 549 bool ValueConversionTraits<webdriver::SkipParsing>::SetFromValue(
191 const Value* value, const webdriver::SkipParsing* t) { 550 const Value* value, const webdriver::SkipParsing* t) {
192 return true; 551 return true;
193 } 552 }
194 553
195 bool ValueConversionTraits<webdriver::SkipParsing>::CanConvert( 554 bool ValueConversionTraits<webdriver::SkipParsing>::CanConvert(
196 const Value* value) { 555 const Value* value) {
197 return true; 556 return true;
198 } 557 }
OLDNEW
« no previous file with comments | « chrome/test/webdriver/webdriver_util.h ('k') | chrome/test/webdriver/webdriver_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698