Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / glue / glue_serialize.cc
blobf20d848f3fd73f860439f905371e920393739394
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/Platform/chromium/public/WebData.h"
13 #include "third_party/WebKit/Source/Platform/chromium/public/WebHTTPBody.h"
14 #include "third_party/WebKit/Source/Platform/chromium/public/WebPoint.h"
15 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
16 #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h"
17 #include "third_party/WebKit/Source/Platform/chromium/public/WebVector.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSerializedScriptValue.h"
20 #include "ui/gfx/screen.h"
21 #include "webkit/base/file_path_string_conversions.h"
23 using WebKit::WebData;
24 using WebKit::WebHistoryItem;
25 using WebKit::WebHTTPBody;
26 using WebKit::WebPoint;
27 using WebKit::WebSerializedScriptValue;
28 using WebKit::WebString;
29 using WebKit::WebUChar;
30 using WebKit::WebVector;
32 namespace webkit_glue {
34 namespace {
36 enum IncludeFormData {
37 NEVER_INCLUDE_FORM_DATA,
38 INCLUDE_FORM_DATA_WITHOUT_PASSWORDS,
39 ALWAYS_INCLUDE_FORM_DATA
42 struct SerializeObject {
43 SerializeObject() : version(0) {}
44 SerializeObject(const char* data, int len)
45 : pickle(data, len), version(0) { iter = PickleIterator(pickle); }
47 std::string GetAsString() {
48 return std::string(static_cast<const char*>(pickle.data()), pickle.size());
51 Pickle pickle;
52 mutable PickleIterator iter;
53 mutable int version;
56 // TODO(mpcomplete): obsolete versions 1 and 2 after 1/1/2008.
57 // Version ID used in reading/writing history items.
58 // 1: Initial revision.
59 // 2: Added case for NULL string versus "". Version 2 code can read Version 1
60 // data, but not vice versa.
61 // 3: Version 2 was broken, it stored number of WebUChars, not number of bytes.
62 // This version checks and reads v1 and v2 correctly.
63 // 4: Adds support for storing FormData::identifier().
64 // 5: Adds support for empty FormData
65 // 6: Adds support for documentSequenceNumbers
66 // 7: Adds support for stateObject
67 // 8: Adds support for file range and modification time
68 // 9: Adds support for itemSequenceNumbers
69 // 10: Adds support for blob
70 // 11: Adds support for pageScaleFactor
71 // 12: Adds support for hasPasswordData in HTTP body
72 // 13: Adds support for URL (FileSystem URL)
73 // Should be const, but unit tests may modify it.
75 // NOTE: If the version is -1, then the pickle contains only a URL string.
76 // See CreateHistoryStateForURL.
78 int kVersion = 13;
80 // A bunch of convenience functions to read/write to SerializeObjects.
81 // The serializers assume the input data is in the correct format and so does
82 // no error checking.
83 inline void WriteData(const void* data, int length, SerializeObject* obj) {
84 obj->pickle.WriteData(static_cast<const char*>(data), length);
87 inline void ReadData(const SerializeObject* obj, const void** data,
88 int* length) {
89 const char* tmp;
90 if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
91 *data = tmp;
92 } else {
93 *data = NULL;
94 *length = 0;
98 inline bool ReadBytes(const SerializeObject* obj, const void** data,
99 int length) {
100 const char *tmp;
101 if (!obj->pickle.ReadBytes(&obj->iter, &tmp, length))
102 return false;
103 *data = tmp;
104 return true;
107 inline void WriteInteger(int data, SerializeObject* obj) {
108 obj->pickle.WriteInt(data);
111 inline int ReadInteger(const SerializeObject* obj) {
112 int tmp;
113 if (obj->pickle.ReadInt(&obj->iter, &tmp))
114 return tmp;
115 return 0;
118 inline void WriteInteger64(int64 data, SerializeObject* obj) {
119 obj->pickle.WriteInt64(data);
122 inline int64 ReadInteger64(const SerializeObject* obj) {
123 int64 tmp = 0;
124 obj->pickle.ReadInt64(&obj->iter, &tmp);
125 return tmp;
128 inline void WriteReal(double data, SerializeObject* obj) {
129 WriteData(&data, sizeof(double), obj);
132 inline double ReadReal(const SerializeObject* obj) {
133 const void* tmp = NULL;
134 int length = 0;
135 double value = 0.0;
136 ReadData(obj, &tmp, &length);
137 if (tmp && length >= static_cast<int>(sizeof(double))) {
138 // Use memcpy, as tmp may not be correctly aligned.
139 memcpy(&value, tmp, sizeof(double));
141 return value;
144 inline void WriteBoolean(bool data, SerializeObject* obj) {
145 obj->pickle.WriteInt(data ? 1 : 0);
148 inline bool ReadBoolean(const SerializeObject* obj) {
149 bool tmp;
150 if (obj->pickle.ReadBool(&obj->iter, &tmp))
151 return tmp;
152 return false;
155 inline void WriteGURL(const GURL& url, SerializeObject* obj) {
156 obj->pickle.WriteString(url.possibly_invalid_spec());
159 inline GURL ReadGURL(const SerializeObject* obj) {
160 std::string spec;
161 if (obj->pickle.ReadString(&obj->iter, &spec))
162 return GURL(spec);
163 return GURL();
166 // Read/WriteString pickle the WebString as <int length><WebUChar* data>.
167 // If length == -1, then the WebString itself is NULL (WebString()).
168 // Otherwise the length is the number of WebUChars (not bytes) in the WebString.
169 inline void WriteString(const WebString& str, SerializeObject* obj) {
170 switch (kVersion) {
171 case 1:
172 // Version 1 writes <length in bytes><string data>.
173 // It saves WebString() and "" as "".
174 obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
175 obj->pickle.WriteBytes(str.data(), str.length() * sizeof(WebUChar));
176 break;
177 case 2:
178 // Version 2 writes <length in WebUChar><string data>.
179 // It uses -1 in the length field to mean WebString().
180 if (str.isNull()) {
181 obj->pickle.WriteInt(-1);
182 } else {
183 obj->pickle.WriteInt(str.length());
184 obj->pickle.WriteBytes(str.data(),
185 str.length() * sizeof(WebUChar));
187 break;
188 default:
189 // Version 3+ writes <length in bytes><string data>.
190 // It uses -1 in the length field to mean WebString().
191 if (str.isNull()) {
192 obj->pickle.WriteInt(-1);
193 } else {
194 obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
195 obj->pickle.WriteBytes(str.data(),
196 str.length() * sizeof(WebUChar));
198 break;
202 // This reads a serialized WebString from obj. If a string can't be read,
203 // WebString() is returned.
204 inline WebString ReadString(const SerializeObject* obj) {
205 int length;
207 // Versions 1, 2, and 3 all start with an integer.
208 if (!obj->pickle.ReadInt(&obj->iter, &length))
209 return WebString();
211 // Starting with version 2, -1 means WebString().
212 if (length == -1)
213 return WebString();
215 // In version 2, the length field was the length in WebUChars.
216 // In version 1 and 3 it is the length in bytes.
217 int bytes = length;
218 if (obj->version == 2)
219 bytes *= sizeof(WebUChar);
221 const void* data;
222 if (!ReadBytes(obj, &data, bytes))
223 return WebString();
224 return WebString(static_cast<const WebUChar*>(data),
225 bytes / sizeof(WebUChar));
228 // Writes a Vector of Strings into a SerializeObject for serialization.
229 void WriteStringVector(
230 const WebVector<WebString>& data, SerializeObject* obj) {
231 WriteInteger(static_cast<int>(data.size()), obj);
232 for (size_t i = 0, c = data.size(); i < c; ++i) {
233 unsigned ui = static_cast<unsigned>(i); // sigh
234 WriteString(data[ui], obj);
238 WebVector<WebString> ReadStringVector(const SerializeObject* obj) {
239 int num_elements = ReadInteger(obj);
240 WebVector<WebString> result(static_cast<size_t>(num_elements));
241 for (int i = 0; i < num_elements; ++i)
242 result[i] = ReadString(obj);
243 return result;
246 // Writes a FormData object into a SerializeObject for serialization.
247 void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
248 WriteBoolean(!http_body.isNull(), obj);
250 if (http_body.isNull())
251 return;
253 WriteInteger(static_cast<int>(http_body.elementCount()), obj);
254 WebHTTPBody::Element element;
255 for (size_t i = 0; http_body.elementAt(i, element); ++i) {
256 WriteInteger(element.type, obj);
257 if (element.type == WebHTTPBody::Element::TypeData) {
258 WriteData(element.data.data(), static_cast<int>(element.data.size()),
259 obj);
260 } else if (element.type == WebHTTPBody::Element::TypeFile) {
261 WriteString(element.filePath, obj);
262 WriteInteger64(element.fileStart, obj);
263 WriteInteger64(element.fileLength, obj);
264 WriteReal(element.modificationTime, obj);
265 } else if (element.type == WebHTTPBody::Element::TypeURL) {
266 WriteGURL(element.url, obj);
267 WriteInteger64(element.fileStart, obj);
268 WriteInteger64(element.fileLength, obj);
269 WriteReal(element.modificationTime, obj);
270 } else {
271 WriteGURL(element.url, obj);
274 WriteInteger64(http_body.identifier(), obj);
275 WriteBoolean(http_body.containsPasswordData(), obj);
278 WebHTTPBody ReadFormData(const SerializeObject* obj) {
279 // In newer versions, an initial boolean indicates if we have form data.
280 if (obj->version >= 5 && !ReadBoolean(obj))
281 return WebHTTPBody();
283 // In older versions, 0 elements implied no form data.
284 int num_elements = ReadInteger(obj);
285 if (num_elements == 0 && obj->version < 5)
286 return WebHTTPBody();
288 WebHTTPBody http_body;
289 http_body.initialize();
291 for (int i = 0; i < num_elements; ++i) {
292 int type = ReadInteger(obj);
293 if (type == WebHTTPBody::Element::TypeData) {
294 const void* data;
295 int length = -1;
296 ReadData(obj, &data, &length);
297 if (length >= 0)
298 http_body.appendData(WebData(static_cast<const char*>(data), length));
299 } else if (type == WebHTTPBody::Element::TypeFile) {
300 WebString file_path = ReadString(obj);
301 long long file_start = 0;
302 long long file_length = -1;
303 double modification_time = 0.0;
304 if (obj->version >= 8) {
305 file_start = ReadInteger64(obj);
306 file_length = ReadInteger64(obj);
307 modification_time = ReadReal(obj);
309 http_body.appendFileRange(file_path, file_start, file_length,
310 modification_time);
311 } else if (type == WebHTTPBody::Element::TypeURL) {
312 GURL url = ReadGURL(obj);
313 long long file_start = 0;
314 long long file_length = -1;
315 double modification_time = 0.0;
316 file_start = ReadInteger64(obj);
317 file_length = ReadInteger64(obj);
318 modification_time = ReadReal(obj);
319 http_body.appendURLRange(url, file_start, file_length,
320 modification_time);
321 } else if (obj->version >= 10) {
322 GURL blob_url = ReadGURL(obj);
323 http_body.appendBlob(blob_url);
326 if (obj->version >= 4)
327 http_body.setIdentifier(ReadInteger64(obj));
329 if (obj->version >= 12)
330 http_body.setContainsPasswordData(ReadBoolean(obj));
332 return http_body;
335 // Writes the HistoryItem data into the SerializeObject object for
336 // serialization.
337 void WriteHistoryItem(
338 const WebHistoryItem& item, SerializeObject* obj) {
339 // WARNING: This data may be persisted for later use. As such, care must be
340 // taken when changing the serialized format. If a new field needs to be
341 // written, only adding at the end will make it easier to deal with loading
342 // older versions. Similarly, this should NOT save fields with sensitive
343 // data, such as password fields.
344 WriteInteger(kVersion, obj);
345 WriteString(item.urlString(), obj);
346 WriteString(item.originalURLString(), obj);
347 WriteString(item.target(), obj);
348 WriteString(item.parent(), obj);
349 WriteString(item.title(), obj);
350 WriteString(item.alternateTitle(), obj);
351 WriteReal(item.lastVisitedTime(), obj);
352 WriteInteger(item.scrollOffset().x, obj);
353 WriteInteger(item.scrollOffset().y, obj);
354 WriteBoolean(item.isTargetItem(), obj);
355 WriteInteger(item.visitCount(), obj);
356 WriteString(item.referrer(), obj);
358 WriteStringVector(item.documentState(), obj);
360 if (kVersion >= 11)
361 WriteReal(item.pageScaleFactor(), obj);
362 if (kVersion >= 9)
363 WriteInteger64(item.itemSequenceNumber(), obj);
364 if (kVersion >= 6)
365 WriteInteger64(item.documentSequenceNumber(), obj);
366 if (kVersion >= 7) {
367 bool has_state_object = !item.stateObject().isNull();
368 WriteBoolean(has_state_object, obj);
369 if (has_state_object)
370 WriteString(item.stateObject().toString(), obj);
373 // Yes, the referrer is written twice. This is for backwards
374 // compatibility with the format.
375 WriteFormData(item.httpBody(), obj);
376 WriteString(item.httpContentType(), obj);
377 WriteString(item.referrer(), obj);
379 // Subitems
380 const WebVector<WebHistoryItem>& children = item.children();
381 WriteInteger(static_cast<int>(children.size()), obj);
382 for (size_t i = 0, c = children.size(); i < c; ++i)
383 WriteHistoryItem(children[i], obj);
386 // Creates a new HistoryItem tree based on the serialized string.
387 // Assumes the data is in the format returned by WriteHistoryItem.
388 WebHistoryItem ReadHistoryItem(
389 const SerializeObject* obj,
390 IncludeFormData include_form_data,
391 bool include_scroll_offset) {
392 // See note in WriteHistoryItem. on this.
393 obj->version = ReadInteger(obj);
395 if (obj->version == -1) {
396 GURL url = ReadGURL(obj);
397 WebHistoryItem item;
398 item.initialize();
399 item.setURLString(WebString::fromUTF8(url.possibly_invalid_spec()));
400 return item;
403 if (obj->version > kVersion || obj->version < 1)
404 return WebHistoryItem();
406 WebHistoryItem item;
407 item.initialize();
409 item.setURLString(ReadString(obj));
410 item.setOriginalURLString(ReadString(obj));
411 item.setTarget(ReadString(obj));
412 item.setParent(ReadString(obj));
413 item.setTitle(ReadString(obj));
414 item.setAlternateTitle(ReadString(obj));
415 item.setLastVisitedTime(ReadReal(obj));
417 int x = ReadInteger(obj);
418 int y = ReadInteger(obj);
419 if (include_scroll_offset)
420 item.setScrollOffset(WebPoint(x, y));
422 item.setIsTargetItem(ReadBoolean(obj));
423 item.setVisitCount(ReadInteger(obj));
424 item.setReferrer(ReadString(obj));
426 item.setDocumentState(ReadStringVector(obj));
428 if (obj->version >= 11)
429 item.setPageScaleFactor(ReadReal(obj));
430 if (obj->version >= 9)
431 item.setItemSequenceNumber(ReadInteger64(obj));
432 if (obj->version >= 6)
433 item.setDocumentSequenceNumber(ReadInteger64(obj));
434 if (obj->version >= 7) {
435 bool has_state_object = ReadBoolean(obj);
436 if (has_state_object) {
437 item.setStateObject(
438 WebSerializedScriptValue::fromString(ReadString(obj)));
442 // The extra referrer string is read for backwards compat.
443 const WebHTTPBody& http_body = ReadFormData(obj);
444 const WebString& http_content_type = ReadString(obj);
445 ALLOW_UNUSED const WebString& unused_referrer = ReadString(obj);
446 if (include_form_data == ALWAYS_INCLUDE_FORM_DATA ||
447 (include_form_data == INCLUDE_FORM_DATA_WITHOUT_PASSWORDS &&
448 !http_body.isNull() && !http_body.containsPasswordData())) {
449 // Include the full HTTP body.
450 item.setHTTPBody(http_body);
451 item.setHTTPContentType(http_content_type);
452 } else if (!http_body.isNull()) {
453 // Don't include the data in the HTTP body, but include its identifier. This
454 // enables fetching data from the cache.
455 WebHTTPBody empty_http_body;
456 empty_http_body.initialize();
457 empty_http_body.setIdentifier(http_body.identifier());
458 item.setHTTPBody(empty_http_body);
461 #if defined(OS_ANDROID)
462 if (obj->version == 11) {
463 // Now-unused values that shipped in this version of Chrome for Android when
464 // it was on a private branch.
465 ReadReal(obj);
466 ReadBoolean(obj);
468 // In this version, pageScaleFactor included deviceScaleFactor and scroll
469 // offsets were premultiplied by pageScaleFactor.
470 if (item.pageScaleFactor()) {
471 if (include_scroll_offset)
472 item.setScrollOffset(
473 WebPoint(item.scrollOffset().x / item.pageScaleFactor(),
474 item.scrollOffset().y / item.pageScaleFactor()));
475 item.setPageScaleFactor(item.pageScaleFactor() /
476 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()
477 .device_scale_factor());
480 #endif
482 // Subitems
483 int num_children = ReadInteger(obj);
484 for (int i = 0; i < num_children; ++i)
485 item.appendToChildren(ReadHistoryItem(obj,
486 include_form_data,
487 include_scroll_offset));
489 return item;
492 // Reconstruct a HistoryItem from a string, using our JSON Value deserializer.
493 // This assumes that the given serialized string has all the required key,value
494 // pairs, and does minimal error checking. The form data of the post is restored
495 // if |include_form_data| is |ALWAYS_INCLUDE_FORM_DATA| or if the data doesn't
496 // contain passwords and |include_form_data| is
497 // |INCLUDE_FORM_DATA_WITHOUT_PASSWORDS|. Otherwise the form data is empty. If
498 // |include_scroll_offset| is true, the scroll offset is restored.
499 WebHistoryItem HistoryItemFromString(
500 const std::string& serialized_item,
501 IncludeFormData include_form_data,
502 bool include_scroll_offset) {
503 if (serialized_item.empty())
504 return WebHistoryItem();
506 SerializeObject obj(serialized_item.data(),
507 static_cast<int>(serialized_item.length()));
508 return ReadHistoryItem(&obj, include_form_data, include_scroll_offset);
511 } // namespace
513 // Serialize a HistoryItem to a string, using our JSON Value serializer.
514 std::string HistoryItemToString(const WebHistoryItem& item) {
515 if (item.isNull())
516 return std::string();
518 SerializeObject obj;
519 WriteHistoryItem(item, &obj);
520 return obj.GetAsString();
523 WebHistoryItem HistoryItemFromString(const std::string& serialized_item) {
524 return HistoryItemFromString(serialized_item, ALWAYS_INCLUDE_FORM_DATA, true);
527 std::vector<base::FilePath> FilePathsFromHistoryState(
528 const std::string& content_state) {
529 std::vector<base::FilePath> to_return;
530 // TODO(darin): We should avoid using the WebKit API here, so that we do not
531 // need to have WebKit initialized before calling this method.
532 const WebHistoryItem& item =
533 HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, true);
534 if (item.isNull()) {
535 // Couldn't parse the string.
536 return to_return;
538 const WebVector<WebString> file_paths = item.getReferencedFilePaths();
539 for (size_t i = 0; i < file_paths.size(); ++i)
540 to_return.push_back(webkit_base::WebStringToFilePath(file_paths[i]));
541 return to_return;
544 // For testing purposes only.
545 void HistoryItemToVersionedString(const WebHistoryItem& item, int version,
546 std::string* serialized_item) {
547 if (item.isNull()) {
548 serialized_item->clear();
549 return;
552 // Temporarily change the version.
553 int real_version = kVersion;
554 kVersion = version;
556 SerializeObject obj;
557 WriteHistoryItem(item, &obj);
558 *serialized_item = obj.GetAsString();
560 kVersion = real_version;
563 int HistoryItemCurrentVersion() {
564 return kVersion;
567 std::string RemoveFormDataFromHistoryState(const std::string& content_state) {
568 // TODO(darin): We should avoid using the WebKit API here, so that we do not
569 // need to have WebKit initialized before calling this method.
570 const WebHistoryItem& item =
571 HistoryItemFromString(content_state, NEVER_INCLUDE_FORM_DATA, true);
572 if (item.isNull()) {
573 // Couldn't parse the string, return an empty string.
574 return std::string();
577 return HistoryItemToString(item);
580 std::string RemovePasswordDataFromHistoryState(
581 const std::string& content_state) {
582 // TODO(darin): We should avoid using the WebKit API here, so that we do not
583 // need to have WebKit initialized before calling this method.
584 const WebHistoryItem& item =
585 HistoryItemFromString(
586 content_state, INCLUDE_FORM_DATA_WITHOUT_PASSWORDS, true);
587 if (item.isNull()) {
588 // Couldn't parse the string, return an empty string.
589 return std::string();
592 return HistoryItemToString(item);
595 std::string RemoveScrollOffsetFromHistoryState(
596 const std::string& content_state) {
597 // TODO(darin): We should avoid using the WebKit API here, so that we do not
598 // need to have WebKit initialized before calling this method.
599 const WebHistoryItem& item =
600 HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, false);
601 if (item.isNull()) {
602 // Couldn't parse the string, return an empty string.
603 return std::string();
606 return HistoryItemToString(item);
609 std::string CreateHistoryStateForURL(const GURL& url) {
610 // We avoid using the WebKit API here, so that we do not need to have WebKit
611 // initialized before calling this method. Instead, we write a simple
612 // serialization of the given URL with a dummy version number of -1. This
613 // will be interpreted by ReadHistoryItem as a request to create a default
614 // WebHistoryItem.
615 SerializeObject obj;
616 WriteInteger(-1, &obj);
617 WriteGURL(url, &obj);
618 return obj.GetAsString();
621 } // namespace webkit_glue