[Mac] PepperFlash default on DEV channel.
[chromium-blink-merge.git] / webkit / glue / glue_serialize.cc
blob4ee3bec89b80a25b51fb43dacf50eb225a2fad03
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.
5 #include "webkit/glue/glue_serialize.h"
7 #include <string>
9 #include "base/pickle.h"
10 #include "base/utf_string_conversions.h"
11 #include "googleurl/src/gurl.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebData.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebHTTPBody.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
20 #include "webkit/glue/webkit_glue.h"
22 using WebKit::WebData;
23 using WebKit::WebHistoryItem;
24 using WebKit::WebHTTPBody;
25 using WebKit::WebPoint;
26 using WebKit::WebSerializedScriptValue;
27 using WebKit::WebString;
28 using WebKit::WebUChar;
29 using WebKit::WebVector;
31 namespace webkit_glue {
33 namespace {
35 enum IncludeFormData {
36 NEVER_INCLUDE_FORM_DATA,
37 INCLUDE_FORM_DATA_WITHOUT_PASSWORDS,
38 ALWAYS_INCLUDE_FORM_DATA
41 struct SerializeObject {
42 SerializeObject() : version(0) {}
43 SerializeObject(const char* data, int len)
44 : pickle(data, len), version(0) { iter = PickleIterator(pickle); }
46 std::string GetAsString() {
47 return std::string(static_cast<const char*>(pickle.data()), pickle.size());
50 Pickle pickle;
51 mutable PickleIterator iter;
52 mutable int version;
55 // TODO(mpcomplete): obsolete versions 1 and 2 after 1/1/2008.
56 // Version ID used in reading/writing history items.
57 // 1: Initial revision.
58 // 2: Added case for NULL string versus "". Version 2 code can read Version 1
59 // data, but not vice versa.
60 // 3: Version 2 was broken, it stored number of WebUChars, not number of bytes.
61 // This version checks and reads v1 and v2 correctly.
62 // 4: Adds support for storing FormData::identifier().
63 // 5: Adds support for empty FormData
64 // 6: Adds support for documentSequenceNumbers
65 // 7: Adds support for stateObject
66 // 8: Adds support for file range and modification time
67 // 9: Adds support for itemSequenceNumbers
68 // 10: Adds support for blob
69 // 11: Adds support for pageScaleFactor
70 // 12: Adds support for hasPasswordData in HTTP body
71 // Should be const, but unit tests may modify it.
73 // NOTE: If the version is -1, then the pickle contains only a URL string.
74 // See CreateHistoryStateForURL.
76 int kVersion = 12;
78 // A bunch of convenience functions to read/write to SerializeObjects.
79 // The serializers assume the input data is in the correct format and so does
80 // no error checking.
81 inline void WriteData(const void* data, int length, SerializeObject* obj) {
82 obj->pickle.WriteData(static_cast<const char*>(data), length);
85 inline void ReadData(const SerializeObject* obj, const void** data,
86 int* length) {
87 const char* tmp;
88 if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
89 *data = tmp;
90 } else {
91 *data = NULL;
92 *length = 0;
96 inline bool ReadBytes(const SerializeObject* obj, const void** data,
97 int length) {
98 const char *tmp;
99 if (!obj->pickle.ReadBytes(&obj->iter, &tmp, length))
100 return false;
101 *data = tmp;
102 return true;
105 inline void WriteInteger(int data, SerializeObject* obj) {
106 obj->pickle.WriteInt(data);
109 inline int ReadInteger(const SerializeObject* obj) {
110 int tmp;
111 if (obj->pickle.ReadInt(&obj->iter, &tmp))
112 return tmp;
113 return 0;
116 inline void WriteInteger64(int64 data, SerializeObject* obj) {
117 obj->pickle.WriteInt64(data);
120 inline int64 ReadInteger64(const SerializeObject* obj) {
121 int64 tmp = 0;
122 obj->pickle.ReadInt64(&obj->iter, &tmp);
123 return tmp;
126 inline void WriteReal(double data, SerializeObject* obj) {
127 WriteData(&data, sizeof(double), obj);
130 inline double ReadReal(const SerializeObject* obj) {
131 const void* tmp = NULL;
132 int length = 0;
133 ReadData(obj, &tmp, &length);
134 if (tmp && length > 0 && length >= static_cast<int>(sizeof(0.0)))
135 return *static_cast<const double*>(tmp);
136 else
137 return 0.0;
140 inline void WriteBoolean(bool data, SerializeObject* obj) {
141 obj->pickle.WriteInt(data ? 1 : 0);
144 inline bool ReadBoolean(const SerializeObject* obj) {
145 bool tmp;
146 if (obj->pickle.ReadBool(&obj->iter, &tmp))
147 return tmp;
148 return false;
151 inline void WriteGURL(const GURL& url, SerializeObject* obj) {
152 obj->pickle.WriteString(url.possibly_invalid_spec());
155 inline GURL ReadGURL(const SerializeObject* obj) {
156 std::string spec;
157 if (obj->pickle.ReadString(&obj->iter, &spec))
158 return GURL(spec);
159 return GURL();
162 // Read/WriteString pickle the WebString as <int length><WebUChar* data>.
163 // If length == -1, then the WebString itself is NULL (WebString()).
164 // Otherwise the length is the number of WebUChars (not bytes) in the WebString.
165 inline void WriteString(const WebString& str, SerializeObject* obj) {
166 switch (kVersion) {
167 case 1:
168 // Version 1 writes <length in bytes><string data>.
169 // It saves WebString() and "" as "".
170 obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
171 obj->pickle.WriteBytes(str.data(), str.length() * sizeof(WebUChar));
172 break;
173 case 2:
174 // Version 2 writes <length in WebUChar><string data>.
175 // It uses -1 in the length field to mean WebString().
176 if (str.isNull()) {
177 obj->pickle.WriteInt(-1);
178 } else {
179 obj->pickle.WriteInt(str.length());
180 obj->pickle.WriteBytes(str.data(),
181 str.length() * sizeof(WebUChar));
183 break;
184 default:
185 // Version 3+ writes <length in bytes><string data>.
186 // It uses -1 in the length field to mean WebString().
187 if (str.isNull()) {
188 obj->pickle.WriteInt(-1);
189 } else {
190 obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
191 obj->pickle.WriteBytes(str.data(),
192 str.length() * sizeof(WebUChar));
194 break;
198 // This reads a serialized WebString from obj. If a string can't be read,
199 // WebString() is returned.
200 inline WebString ReadString(const SerializeObject* obj) {
201 int length;
203 // Versions 1, 2, and 3 all start with an integer.
204 if (!obj->pickle.ReadInt(&obj->iter, &length))
205 return WebString();
207 // Starting with version 2, -1 means WebString().
208 if (length == -1)
209 return WebString();
211 // In version 2, the length field was the length in WebUChars.
212 // In version 1 and 3 it is the length in bytes.
213 int bytes = length;
214 if (obj->version == 2)
215 bytes *= sizeof(WebUChar);
217 const void* data;
218 if (!ReadBytes(obj, &data, bytes))
219 return WebString();
220 return WebString(static_cast<const WebUChar*>(data),
221 bytes / sizeof(WebUChar));
224 // Writes a Vector of Strings into a SerializeObject for serialization.
225 void WriteStringVector(
226 const WebVector<WebString>& data, SerializeObject* obj) {
227 WriteInteger(static_cast<int>(data.size()), obj);
228 for (size_t i = 0, c = data.size(); i < c; ++i) {
229 unsigned ui = static_cast<unsigned>(i); // sigh
230 WriteString(data[ui], obj);
234 WebVector<WebString> ReadStringVector(const SerializeObject* obj) {
235 int num_elements = ReadInteger(obj);
236 WebVector<WebString> result(static_cast<size_t>(num_elements));
237 for (int i = 0; i < num_elements; ++i)
238 result[i] = ReadString(obj);
239 return result;
242 // Writes a FormData object into a SerializeObject for serialization.
243 void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
244 WriteBoolean(!http_body.isNull(), obj);
246 if (http_body.isNull())
247 return;
249 WriteInteger(static_cast<int>(http_body.elementCount()), obj);
250 WebHTTPBody::Element element;
251 for (size_t i = 0; http_body.elementAt(i, element); ++i) {
252 WriteInteger(element.type, obj);
253 if (element.type == WebHTTPBody::Element::TypeData) {
254 WriteData(element.data.data(), static_cast<int>(element.data.size()),
255 obj);
256 } else if (element.type == WebHTTPBody::Element::TypeFile) {
257 WriteString(element.filePath, obj);
258 WriteInteger64(element.fileStart, obj);
259 WriteInteger64(element.fileLength, obj);
260 WriteReal(element.modificationTime, obj);
261 } else {
262 WriteGURL(element.blobURL, obj);
265 WriteInteger64(http_body.identifier(), obj);
266 WriteBoolean(http_body.containsPasswordData(), obj);
269 WebHTTPBody ReadFormData(const SerializeObject* obj) {
270 // In newer versions, an initial boolean indicates if we have form data.
271 if (obj->version >= 5 && !ReadBoolean(obj))
272 return WebHTTPBody();
274 // In older versions, 0 elements implied no form data.
275 int num_elements = ReadInteger(obj);
276 if (num_elements == 0 && obj->version < 5)
277 return WebHTTPBody();
279 WebHTTPBody http_body;
280 http_body.initialize();
282 for (int i = 0; i < num_elements; ++i) {
283 int type = ReadInteger(obj);
284 if (type == WebHTTPBody::Element::TypeData) {
285 const void* data;
286 int length = -1;
287 ReadData(obj, &data, &length);
288 if (length >= 0)
289 http_body.appendData(WebData(static_cast<const char*>(data), length));
290 } else if (type == WebHTTPBody::Element::TypeFile) {
291 WebString file_path = ReadString(obj);
292 long long file_start = 0;
293 long long file_length = -1;
294 double modification_time = 0.0;
295 if (obj->version >= 8) {
296 file_start = ReadInteger64(obj);
297 file_length = ReadInteger64(obj);
298 modification_time = ReadReal(obj);
300 http_body.appendFileRange(file_path, file_start, file_length,
301 modification_time);
302 } else if (obj->version >= 10) {
303 GURL blob_url = ReadGURL(obj);
304 http_body.appendBlob(blob_url);
307 if (obj->version >= 4)
308 http_body.setIdentifier(ReadInteger64(obj));
310 if (obj->version >= 12)
311 http_body.setContainsPasswordData(ReadBoolean(obj));
313 return http_body;
316 // Writes the HistoryItem data into the SerializeObject object for
317 // serialization.
318 void WriteHistoryItem(
319 const WebHistoryItem& item, SerializeObject* obj) {
320 // WARNING: This data may be persisted for later use. As such, care must be
321 // taken when changing the serialized format. If a new field needs to be
322 // written, only adding at the end will make it easier to deal with loading
323 // older versions. Similarly, this should NOT save fields with sensitive
324 // data, such as password fields.
325 WriteInteger(kVersion, obj);
326 WriteString(item.urlString(), obj);
327 WriteString(item.originalURLString(), obj);
328 WriteString(item.target(), obj);
329 WriteString(item.parent(), obj);
330 WriteString(item.title(), obj);
331 WriteString(item.alternateTitle(), obj);
332 WriteReal(item.lastVisitedTime(), obj);
333 WriteInteger(item.scrollOffset().x, obj);
334 WriteInteger(item.scrollOffset().y, obj);
335 WriteBoolean(item.isTargetItem(), obj);
336 WriteInteger(item.visitCount(), obj);
337 WriteString(item.referrer(), obj);
339 WriteStringVector(item.documentState(), obj);
341 if (kVersion >= 11)
342 WriteReal(item.pageScaleFactor(), obj);
343 if (kVersion >= 9)
344 WriteInteger64(item.itemSequenceNumber(), obj);
345 if (kVersion >= 6)
346 WriteInteger64(item.documentSequenceNumber(), obj);
347 if (kVersion >= 7) {
348 bool has_state_object = !item.stateObject().isNull();
349 WriteBoolean(has_state_object, obj);
350 if (has_state_object)
351 WriteString(item.stateObject().toString(), obj);
354 // Yes, the referrer is written twice. This is for backwards
355 // compatibility with the format.
356 WriteFormData(item.httpBody(), obj);
357 WriteString(item.httpContentType(), obj);
358 WriteString(item.referrer(), obj);
360 // Subitems
361 const WebVector<WebHistoryItem>& children = item.children();
362 WriteInteger(static_cast<int>(children.size()), obj);
363 for (size_t i = 0, c = children.size(); i < c; ++i)
364 WriteHistoryItem(children[i], obj);
367 // Creates a new HistoryItem tree based on the serialized string.
368 // Assumes the data is in the format returned by WriteHistoryItem.
369 WebHistoryItem ReadHistoryItem(
370 const SerializeObject* obj,
371 IncludeFormData include_form_data,
372 bool include_scroll_offset) {
373 // See note in WriteHistoryItem. on this.
374 obj->version = ReadInteger(obj);
376 if (obj->version == -1) {
377 GURL url = ReadGURL(obj);
378 WebHistoryItem item;
379 item.initialize();
380 item.setURLString(WebString::fromUTF8(url.possibly_invalid_spec()));
381 return item;
384 if (obj->version > kVersion || obj->version < 1)
385 return WebHistoryItem();
387 WebHistoryItem item;
388 item.initialize();
390 item.setURLString(ReadString(obj));
391 item.setOriginalURLString(ReadString(obj));
392 item.setTarget(ReadString(obj));
393 item.setParent(ReadString(obj));
394 item.setTitle(ReadString(obj));
395 item.setAlternateTitle(ReadString(obj));
396 item.setLastVisitedTime(ReadReal(obj));
398 int x = ReadInteger(obj);
399 int y = ReadInteger(obj);
400 if (include_scroll_offset)
401 item.setScrollOffset(WebPoint(x, y));
403 item.setIsTargetItem(ReadBoolean(obj));
404 item.setVisitCount(ReadInteger(obj));
405 item.setReferrer(ReadString(obj));
407 item.setDocumentState(ReadStringVector(obj));
409 if (obj->version >= 11)
410 item.setPageScaleFactor(ReadReal(obj));
411 if (obj->version >= 9)
412 item.setItemSequenceNumber(ReadInteger64(obj));
413 if (obj->version >= 6)
414 item.setDocumentSequenceNumber(ReadInteger64(obj));
415 if (obj->version >= 7) {
416 bool has_state_object = ReadBoolean(obj);
417 if (has_state_object) {
418 item.setStateObject(
419 WebSerializedScriptValue::fromString(ReadString(obj)));
423 // The extra referrer string is read for backwards compat.
424 const WebHTTPBody& http_body = ReadFormData(obj);
425 const WebString& http_content_type = ReadString(obj);
426 ALLOW_UNUSED const WebString& unused_referrer = ReadString(obj);
427 if (include_form_data == ALWAYS_INCLUDE_FORM_DATA ||
428 (include_form_data == INCLUDE_FORM_DATA_WITHOUT_PASSWORDS &&
429 !http_body.isNull() && !http_body.containsPasswordData())) {
430 // Include the full HTTP body.
431 item.setHTTPBody(http_body);
432 item.setHTTPContentType(http_content_type);
433 } else if (!http_body.isNull()) {
434 // Don't include the data in the HTTP body, but include its identifier. This
435 // enables fetching data from the cache.
436 WebHTTPBody empty_http_body;
437 empty_http_body.initialize();
438 empty_http_body.setIdentifier(http_body.identifier());
439 item.setHTTPBody(empty_http_body);
442 // Subitems
443 int num_children = ReadInteger(obj);
444 for (int i = 0; i < num_children; ++i)
445 item.appendToChildren(ReadHistoryItem(obj,
446 include_form_data,
447 include_scroll_offset));
449 return item;
452 // Reconstruct a HistoryItem from a string, using our JSON Value deserializer.
453 // This assumes that the given serialized string has all the required key,value
454 // pairs, and does minimal error checking. The form data of the post is restored
455 // if |include_form_data| is |ALWAYS_INCLUDE_FORM_DATA| or if the data doesn't
456 // contain passwords and |include_form_data| is
457 // |INCLUDE_FORM_DATA_WITHOUT_PASSWORDS|. Otherwise the form data is empty. If
458 // |include_scroll_offset| is true, the scroll offset is restored.
459 WebHistoryItem HistoryItemFromString(
460 const std::string& serialized_item,
461 IncludeFormData include_form_data,
462 bool include_scroll_offset) {
463 if (serialized_item.empty())
464 return WebHistoryItem();
466 SerializeObject obj(serialized_item.data(),
467 static_cast<int>(serialized_item.length()));
468 return ReadHistoryItem(&obj, include_form_data, include_scroll_offset);
470 } // namespace
472 std::string RemoveFormDataFromHistoryState(const std::string& content_state) {
473 // TODO(darin): We should avoid using the WebKit API here, so that we do not
474 // need to have WebKit initialized before calling this method.
475 const WebHistoryItem& item =
476 HistoryItemFromString(content_state, NEVER_INCLUDE_FORM_DATA, true);
477 if (item.isNull()) {
478 // Couldn't parse the string, return an empty string.
479 return std::string();
482 return HistoryItemToString(item);
485 std::string RemovePasswordDataFromHistoryState(
486 const std::string& content_state) {
487 // TODO(darin): We should avoid using the WebKit API here, so that we do not
488 // need to have WebKit initialized before calling this method.
489 const WebHistoryItem& item =
490 HistoryItemFromString(
491 content_state, INCLUDE_FORM_DATA_WITHOUT_PASSWORDS, true);
492 if (item.isNull()) {
493 // Couldn't parse the string, return an empty string.
494 return std::string();
497 return HistoryItemToString(item);
500 std::string RemoveScrollOffsetFromHistoryState(
501 const std::string& content_state) {
502 // TODO(darin): We should avoid using the WebKit API here, so that we do not
503 // need to have WebKit initialized before calling this method.
504 const WebHistoryItem& item =
505 HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, false);
506 if (item.isNull()) {
507 // Couldn't parse the string, return an empty string.
508 return std::string();
511 return HistoryItemToString(item);
514 std::string CreateHistoryStateForURL(const GURL& url) {
515 // We avoid using the WebKit API here, so that we do not need to have WebKit
516 // initialized before calling this method. Instead, we write a simple
517 // serialization of the given URL with a dummy version number of -1. This
518 // will be interpreted by ReadHistoryItem as a request to create a default
519 // WebHistoryItem.
520 SerializeObject obj;
521 WriteInteger(-1, &obj);
522 WriteGURL(url, &obj);
523 return obj.GetAsString();
526 // Serialize a HistoryItem to a string, using our JSON Value serializer.
527 std::string HistoryItemToString(const WebHistoryItem& item) {
528 if (item.isNull())
529 return std::string();
531 SerializeObject obj;
532 WriteHistoryItem(item, &obj);
533 return obj.GetAsString();
536 WebHistoryItem HistoryItemFromString(const std::string& serialized_item) {
537 return HistoryItemFromString(serialized_item, ALWAYS_INCLUDE_FORM_DATA, true);
540 std::vector<FilePath> FilePathsFromHistoryState(
541 const std::string& content_state) {
542 std::vector<FilePath> to_return;
543 // TODO(darin): We should avoid using the WebKit API here, so that we do not
544 // need to have WebKit initialized before calling this method.
545 const WebHistoryItem& item =
546 HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, true);
547 if (item.isNull()) {
548 // Couldn't parse the string.
549 return to_return;
551 const WebHTTPBody& http_body = item.httpBody();
552 if (!http_body.isNull()) {
553 WebHTTPBody::Element element;
554 for (size_t i = 0; i < http_body.elementCount(); ++i) {
555 http_body.elementAt(i, element);
556 if (element.type == WebHTTPBody::Element::TypeFile)
557 to_return.push_back(WebStringToFilePath(element.filePath));
560 return to_return;
563 // For testing purposes only.
564 void HistoryItemToVersionedString(const WebHistoryItem& item, int version,
565 std::string* serialized_item) {
566 if (item.isNull()) {
567 serialized_item->clear();
568 return;
571 // Temporarily change the version.
572 int real_version = kVersion;
573 kVersion = version;
575 SerializeObject obj;
576 WriteHistoryItem(item, &obj);
577 *serialized_item = obj.GetAsString();
579 kVersion = real_version;
582 int HistoryItemCurrentVersion() {
583 return kVersion;
586 } // namespace webkit_glue