summaryrefslogtreecommitdiffstats
path: root/webkit/glue/glue_serialize.cc
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-26 02:02:18 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-26 02:02:18 +0000
commite0185f9fe7ba991f701ac7bb6d8dbafa745a31ab (patch)
treed43a5f87c837ba410e30e0d9095f1cd3e1a9c95c /webkit/glue/glue_serialize.cc
parentd70d82db35eecb586629a05bffc580282c0c30b4 (diff)
downloadchromium_src-e0185f9fe7ba991f701ac7bb6d8dbafa745a31ab.zip
chromium_src-e0185f9fe7ba991f701ac7bb6d8dbafa745a31ab.tar.gz
chromium_src-e0185f9fe7ba991f701ac7bb6d8dbafa745a31ab.tar.bz2
Revert 202188 "Introduce content::PageState."
This change bloated npchrome_frame.dll (see http://build.chromium.org/f/chromium/perf/xp-release/sizes/report.html?=undefined&history=3&rev=202214&graph=npchrome_frame.dll) because content_common.lib's common_param_traits.obj depends on content_common.lib's page_state.obj which, in turn, depends on webkit. This means that consumers of IPC messages in content_common suddenly require all of webkit. > Introduce content::PageState. > > This is a concrete class wrapping a string that contains the > data of a serialized WebKit::WebHistoryItem class. Previously, > we've just passed around these as strings, giving them names > like "state", "content_state" or "history_state". It has been > hard to identify all of the places in the code where these > strings get passed around. A concrete class should make usage > more apparent. Plus, instead of manipulating the strings using > methods from webkit/glue/glue_serialize.h, we can just declare > methods on the PageState class. This makes the code much cleaner. > > This first pass just implements PageState in terms of glue_serialize. > It also adds content/public/renderer/history_item_serialization.h > as the home for PageState to WebKit::WebHistoryItem conversion, > which should ideally only be usable from the renderer process. > (This bit is a step toward resolving bug 237243.) > > page_state.h declares operator==() to support DCHECK_EQ, which > seems consistent with the idea of PageState being a replacement > for std::string. I didn't want to litter tests with calls to > PageState::ToEncodedData(). That would get cumbersome. > > BUG=240426 > R=brettw@chromium.org, tsepez@chromium.org > > Review URL: https://codereview.chromium.org/14985014 TBR=darin@chromium.org Review URL: https://codereview.chromium.org/16068002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202321 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/glue_serialize.cc')
-rw-r--r--webkit/glue/glue_serialize.cc668
1 files changed, 668 insertions, 0 deletions
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc
new file mode 100644
index 0000000..1b5edbd
--- /dev/null
+++ b/webkit/glue/glue_serialize.cc
@@ -0,0 +1,668 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/glue/glue_serialize.h"
+
+#include <string>
+
+#include "base/pickle.h"
+#include "base/utf_string_conversions.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebData.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebHTTPBody.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebPoint.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebVector.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSerializedScriptValue.h"
+#include "ui/gfx/screen.h"
+#include "webkit/base/file_path_string_conversions.h"
+
+using WebKit::WebData;
+using WebKit::WebHistoryItem;
+using WebKit::WebHTTPBody;
+using WebKit::WebPoint;
+using WebKit::WebSerializedScriptValue;
+using WebKit::WebString;
+using WebKit::WebUChar;
+using WebKit::WebVector;
+
+namespace webkit_glue {
+
+namespace {
+
+enum IncludeFormData {
+ NEVER_INCLUDE_FORM_DATA,
+ INCLUDE_FORM_DATA_WITHOUT_PASSWORDS,
+ ALWAYS_INCLUDE_FORM_DATA
+};
+
+struct SerializeObject {
+ SerializeObject() : version(0) {}
+ SerializeObject(const char* data, int len)
+ : pickle(data, len), version(0) { iter = PickleIterator(pickle); }
+
+ std::string GetAsString() {
+ return std::string(static_cast<const char*>(pickle.data()), pickle.size());
+ }
+
+ Pickle pickle;
+ mutable PickleIterator iter;
+ mutable int version;
+};
+
+// TODO(mpcomplete): obsolete versions 1 and 2 after 1/1/2008.
+// Version ID used in reading/writing history items.
+// 1: Initial revision.
+// 2: Added case for NULL string versus "". Version 2 code can read Version 1
+// data, but not vice versa.
+// 3: Version 2 was broken, it stored number of WebUChars, not number of bytes.
+// This version checks and reads v1 and v2 correctly.
+// 4: Adds support for storing FormData::identifier().
+// 5: Adds support for empty FormData
+// 6: Adds support for documentSequenceNumbers
+// 7: Adds support for stateObject
+// 8: Adds support for file range and modification time
+// 9: Adds support for itemSequenceNumbers
+// 10: Adds support for blob
+// 11: Adds support for pageScaleFactor
+// 12: Adds support for hasPasswordData in HTTP body
+// 13: Adds support for URL (FileSystem URL)
+// 14: Adds list of referenced files, version written only for first item.
+// Should be const, but unit tests may modify it.
+//
+// NOTE: If the version is -1, then the pickle contains only a URL string.
+// See CreateHistoryStateForURL.
+//
+int kVersion = 14;
+
+// A bunch of convenience functions to read/write to SerializeObjects.
+// The serializers assume the input data is in the correct format and so does
+// no error checking.
+void WriteData(const void* data, int length, SerializeObject* obj) {
+ obj->pickle.WriteData(static_cast<const char*>(data), length);
+}
+
+void ReadData(const SerializeObject* obj, const void** data, int* length) {
+ const char* tmp;
+ if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
+ *data = tmp;
+ } else {
+ *data = NULL;
+ *length = 0;
+ }
+}
+
+bool ReadBytes(const SerializeObject* obj, const void** data, int length) {
+ const char *tmp;
+ if (!obj->pickle.ReadBytes(&obj->iter, &tmp, length))
+ return false;
+ *data = tmp;
+ return true;
+}
+
+void WriteInteger(int data, SerializeObject* obj) {
+ obj->pickle.WriteInt(data);
+}
+
+int ReadInteger(const SerializeObject* obj) {
+ int tmp;
+ if (obj->pickle.ReadInt(&obj->iter, &tmp))
+ return tmp;
+ return 0;
+}
+
+void ConsumeInteger(const SerializeObject* obj) {
+ int unused ALLOW_UNUSED = ReadInteger(obj);
+}
+
+void WriteInteger64(int64 data, SerializeObject* obj) {
+ obj->pickle.WriteInt64(data);
+}
+
+int64 ReadInteger64(const SerializeObject* obj) {
+ int64 tmp = 0;
+ obj->pickle.ReadInt64(&obj->iter, &tmp);
+ return tmp;
+}
+
+void WriteReal(double data, SerializeObject* obj) {
+ WriteData(&data, sizeof(double), obj);
+}
+
+double ReadReal(const SerializeObject* obj) {
+ const void* tmp = NULL;
+ int length = 0;
+ double value = 0.0;
+ ReadData(obj, &tmp, &length);
+ if (tmp && length >= static_cast<int>(sizeof(double))) {
+ // Use memcpy, as tmp may not be correctly aligned.
+ memcpy(&value, tmp, sizeof(double));
+ }
+ return value;
+}
+
+void WriteBoolean(bool data, SerializeObject* obj) {
+ obj->pickle.WriteInt(data ? 1 : 0);
+}
+
+bool ReadBoolean(const SerializeObject* obj) {
+ bool tmp;
+ if (obj->pickle.ReadBool(&obj->iter, &tmp))
+ return tmp;
+ return false;
+}
+
+void WriteGURL(const GURL& url, SerializeObject* obj) {
+ obj->pickle.WriteString(url.possibly_invalid_spec());
+}
+
+GURL ReadGURL(const SerializeObject* obj) {
+ std::string spec;
+ if (obj->pickle.ReadString(&obj->iter, &spec))
+ return GURL(spec);
+ return GURL();
+}
+
+// Read/WriteString pickle the WebString as <int length><WebUChar* data>.
+// If length == -1, then the WebString itself is NULL (WebString()).
+// Otherwise the length is the number of WebUChars (not bytes) in the WebString.
+void WriteString(const WebString& str, SerializeObject* obj) {
+ switch (kVersion) {
+ case 1:
+ // Version 1 writes <length in bytes><string data>.
+ // It saves WebString() and "" as "".
+ obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
+ obj->pickle.WriteBytes(str.data(), str.length() * sizeof(WebUChar));
+ break;
+ case 2:
+ // Version 2 writes <length in WebUChar><string data>.
+ // It uses -1 in the length field to mean WebString().
+ if (str.isNull()) {
+ obj->pickle.WriteInt(-1);
+ } else {
+ obj->pickle.WriteInt(str.length());
+ obj->pickle.WriteBytes(str.data(),
+ str.length() * sizeof(WebUChar));
+ }
+ break;
+ default:
+ // Version 3+ writes <length in bytes><string data>.
+ // It uses -1 in the length field to mean WebString().
+ if (str.isNull()) {
+ obj->pickle.WriteInt(-1);
+ } else {
+ obj->pickle.WriteInt(str.length() * sizeof(WebUChar));
+ obj->pickle.WriteBytes(str.data(),
+ str.length() * sizeof(WebUChar));
+ }
+ break;
+ }
+}
+
+// This reads a serialized WebString from obj. If a string can't be read,
+// WebString() is returned.
+const WebUChar* ReadStringNoCopy(const SerializeObject* obj, int* num_chars) {
+ int length;
+
+ // Versions 1, 2, and 3 all start with an integer.
+ if (!obj->pickle.ReadInt(&obj->iter, &length))
+ return NULL;
+
+ // Starting with version 2, -1 means WebString().
+ if (length == -1)
+ return NULL;
+
+ // In version 2, the length field was the length in WebUChars.
+ // In version 1 and 3 it is the length in bytes.
+ int bytes = length;
+ if (obj->version == 2)
+ bytes *= sizeof(WebUChar);
+
+ const void* data;
+ if (!ReadBytes(obj, &data, bytes))
+ return NULL;
+
+ if (num_chars)
+ *num_chars = bytes / sizeof(WebUChar);
+ return static_cast<const WebUChar*>(data);
+}
+
+WebString ReadString(const SerializeObject* obj) {
+ int num_chars;
+ const WebUChar* chars = ReadStringNoCopy(obj, &num_chars);
+ return chars ? WebString(chars, num_chars) : WebString();
+}
+
+void ConsumeString(const SerializeObject* obj) {
+ const WebUChar* unused ALLOW_UNUSED = ReadStringNoCopy(obj, NULL);
+}
+
+// Writes a Vector of Strings into a SerializeObject for serialization.
+void WriteStringVector(
+ const WebVector<WebString>& data, SerializeObject* obj) {
+ WriteInteger(static_cast<int>(data.size()), obj);
+ for (size_t i = 0, c = data.size(); i < c; ++i) {
+ unsigned ui = static_cast<unsigned>(i); // sigh
+ WriteString(data[ui], obj);
+ }
+}
+
+WebVector<WebString> ReadStringVector(const SerializeObject* obj) {
+ int num_elements = ReadInteger(obj);
+ WebVector<WebString> result(static_cast<size_t>(num_elements));
+ for (int i = 0; i < num_elements; ++i)
+ result[i] = ReadString(obj);
+ return result;
+}
+
+void ConsumeStringVector(const SerializeObject* obj) {
+ int num_elements = ReadInteger(obj);
+ for (int i = 0; i < num_elements; ++i)
+ ConsumeString(obj);
+}
+
+// Writes a FormData object into a SerializeObject for serialization.
+void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
+ WriteBoolean(!http_body.isNull(), obj);
+
+ if (http_body.isNull())
+ return;
+
+ WriteInteger(static_cast<int>(http_body.elementCount()), obj);
+ WebHTTPBody::Element element;
+ for (size_t i = 0; http_body.elementAt(i, element); ++i) {
+ WriteInteger(element.type, obj);
+ if (element.type == WebHTTPBody::Element::TypeData) {
+ WriteData(element.data.data(), static_cast<int>(element.data.size()),
+ obj);
+ } else if (element.type == WebHTTPBody::Element::TypeFile) {
+ WriteString(element.filePath, obj);
+ WriteInteger64(element.fileStart, obj);
+ WriteInteger64(element.fileLength, obj);
+ WriteReal(element.modificationTime, obj);
+ } else if (element.type == WebHTTPBody::Element::TypeURL) {
+ WriteGURL(element.url, obj);
+ WriteInteger64(element.fileStart, obj);
+ WriteInteger64(element.fileLength, obj);
+ WriteReal(element.modificationTime, obj);
+ } else {
+ WriteGURL(element.url, obj);
+ }
+ }
+ WriteInteger64(http_body.identifier(), obj);
+ WriteBoolean(http_body.containsPasswordData(), obj);
+}
+
+WebHTTPBody ReadFormData(const SerializeObject* obj) {
+ // In newer versions, an initial boolean indicates if we have form data.
+ if (obj->version >= 5 && !ReadBoolean(obj))
+ return WebHTTPBody();
+
+ // In older versions, 0 elements implied no form data.
+ int num_elements = ReadInteger(obj);
+ if (num_elements == 0 && obj->version < 5)
+ return WebHTTPBody();
+
+ WebHTTPBody http_body;
+ http_body.initialize();
+
+ for (int i = 0; i < num_elements; ++i) {
+ int type = ReadInteger(obj);
+ if (type == WebHTTPBody::Element::TypeData) {
+ const void* data;
+ int length = -1;
+ ReadData(obj, &data, &length);
+ if (length >= 0)
+ http_body.appendData(WebData(static_cast<const char*>(data), length));
+ } else if (type == WebHTTPBody::Element::TypeFile) {
+ WebString file_path = ReadString(obj);
+ long long file_start = 0;
+ long long file_length = -1;
+ double modification_time = 0.0;
+ if (obj->version >= 8) {
+ file_start = ReadInteger64(obj);
+ file_length = ReadInteger64(obj);
+ modification_time = ReadReal(obj);
+ }
+ http_body.appendFileRange(file_path, file_start, file_length,
+ modification_time);
+ } else if (type == WebHTTPBody::Element::TypeURL) {
+ GURL url = ReadGURL(obj);
+ long long file_start = 0;
+ long long file_length = -1;
+ double modification_time = 0.0;
+ file_start = ReadInteger64(obj);
+ file_length = ReadInteger64(obj);
+ modification_time = ReadReal(obj);
+ http_body.appendURLRange(url, file_start, file_length,
+ modification_time);
+ } else if (obj->version >= 10) {
+ GURL blob_url = ReadGURL(obj);
+ http_body.appendBlob(blob_url);
+ }
+ }
+ if (obj->version >= 4)
+ http_body.setIdentifier(ReadInteger64(obj));
+
+ if (obj->version >= 12)
+ http_body.setContainsPasswordData(ReadBoolean(obj));
+
+ return http_body;
+}
+
+// Writes the HistoryItem data into the SerializeObject object for
+// serialization.
+void WriteHistoryItem(
+ const WebHistoryItem& item, SerializeObject* obj, bool is_top) {
+ // WARNING: This data may be persisted for later use. As such, care must be
+ // taken when changing the serialized format. If a new field needs to be
+ // written, only adding at the end will make it easier to deal with loading
+ // older versions. Similarly, this should NOT save fields with sensitive
+ // data, such as password fields.
+
+ if (kVersion >= 14) {
+ if (is_top) {
+ WriteInteger(kVersion, obj);
+
+ // Insert the list of referenced files, so they can be extracted easily
+ // from the serialized data (avoiding the need to call into Blink again).
+ WriteStringVector(item.getReferencedFilePaths(), obj);
+ }
+ } else {
+ WriteInteger(kVersion, obj);
+ }
+
+ WriteString(item.urlString(), obj);
+ WriteString(item.originalURLString(), obj);
+ WriteString(item.target(), obj);
+ WriteString(item.parent(), obj);
+ WriteString(item.title(), obj);
+ WriteString(item.alternateTitle(), obj);
+ WriteReal(item.lastVisitedTime(), obj);
+ WriteInteger(item.scrollOffset().x, obj);
+ WriteInteger(item.scrollOffset().y, obj);
+ WriteBoolean(item.isTargetItem(), obj);
+ WriteInteger(item.visitCount(), obj);
+ WriteString(item.referrer(), obj);
+
+ WriteStringVector(item.documentState(), obj);
+
+ if (kVersion >= 11)
+ WriteReal(item.pageScaleFactor(), obj);
+ if (kVersion >= 9)
+ WriteInteger64(item.itemSequenceNumber(), obj);
+ if (kVersion >= 6)
+ WriteInteger64(item.documentSequenceNumber(), obj);
+ if (kVersion >= 7) {
+ bool has_state_object = !item.stateObject().isNull();
+ WriteBoolean(has_state_object, obj);
+ if (has_state_object)
+ WriteString(item.stateObject().toString(), obj);
+ }
+
+ WriteFormData(item.httpBody(), obj);
+ WriteString(item.httpContentType(), obj);
+ if (kVersion < 14)
+ WriteString(item.referrer(), obj);
+
+ // Subitems
+ const WebVector<WebHistoryItem>& children = item.children();
+ WriteInteger(static_cast<int>(children.size()), obj);
+ for (size_t i = 0, c = children.size(); i < c; ++i)
+ WriteHistoryItem(children[i], obj, false);
+}
+
+// Creates a new HistoryItem tree based on the serialized string.
+// Assumes the data is in the format returned by WriteHistoryItem.
+WebHistoryItem ReadHistoryItem(
+ const SerializeObject* obj,
+ IncludeFormData include_form_data,
+ bool include_scroll_offset,
+ bool is_top) {
+ if (is_top) {
+ obj->version = ReadInteger(obj);
+
+ if (obj->version == -1) {
+ GURL url = ReadGURL(obj);
+ WebHistoryItem item;
+ item.initialize();
+ item.setURLString(WebString::fromUTF8(url.possibly_invalid_spec()));
+ return item;
+ }
+
+ if (obj->version > kVersion || obj->version < 1)
+ return WebHistoryItem();
+
+ if (obj->version >= 14)
+ ConsumeStringVector(obj); // Skip over list of referenced files.
+ } else if (obj->version < 14) {
+ ConsumeInteger(obj); // Skip over redundant version field.
+ }
+
+ WebHistoryItem item;
+ item.initialize();
+
+ item.setURLString(ReadString(obj));
+ item.setOriginalURLString(ReadString(obj));
+ item.setTarget(ReadString(obj));
+ item.setParent(ReadString(obj));
+ item.setTitle(ReadString(obj));
+ item.setAlternateTitle(ReadString(obj));
+ item.setLastVisitedTime(ReadReal(obj));
+
+ int x = ReadInteger(obj);
+ int y = ReadInteger(obj);
+ if (include_scroll_offset)
+ item.setScrollOffset(WebPoint(x, y));
+
+ item.setIsTargetItem(ReadBoolean(obj));
+ item.setVisitCount(ReadInteger(obj));
+ item.setReferrer(ReadString(obj));
+
+ item.setDocumentState(ReadStringVector(obj));
+
+ if (obj->version >= 11)
+ item.setPageScaleFactor(ReadReal(obj));
+ if (obj->version >= 9)
+ item.setItemSequenceNumber(ReadInteger64(obj));
+ if (obj->version >= 6)
+ item.setDocumentSequenceNumber(ReadInteger64(obj));
+ if (obj->version >= 7) {
+ bool has_state_object = ReadBoolean(obj);
+ if (has_state_object) {
+ item.setStateObject(
+ WebSerializedScriptValue::fromString(ReadString(obj)));
+ }
+ }
+
+ // The extra referrer string is read for backwards compat.
+ const WebHTTPBody& http_body = ReadFormData(obj);
+ const WebString& http_content_type = ReadString(obj);
+
+ if (obj->version < 14)
+ ConsumeString(obj); // Skip unused referrer string.
+
+ if (include_form_data == ALWAYS_INCLUDE_FORM_DATA ||
+ (include_form_data == INCLUDE_FORM_DATA_WITHOUT_PASSWORDS &&
+ !http_body.isNull() && !http_body.containsPasswordData())) {
+ // Include the full HTTP body.
+ item.setHTTPBody(http_body);
+ item.setHTTPContentType(http_content_type);
+ } else if (!http_body.isNull()) {
+ // Don't include the data in the HTTP body, but include its identifier. This
+ // enables fetching data from the cache.
+ WebHTTPBody empty_http_body;
+ empty_http_body.initialize();
+ empty_http_body.setIdentifier(http_body.identifier());
+ item.setHTTPBody(empty_http_body);
+ }
+
+#if defined(OS_ANDROID)
+ if (obj->version == 11) {
+ // Now-unused values that shipped in this version of Chrome for Android when
+ // it was on a private branch.
+ ReadReal(obj);
+ ReadBoolean(obj);
+
+ // In this version, pageScaleFactor included deviceScaleFactor and scroll
+ // offsets were premultiplied by pageScaleFactor.
+ if (item.pageScaleFactor()) {
+ if (include_scroll_offset)
+ item.setScrollOffset(
+ WebPoint(item.scrollOffset().x / item.pageScaleFactor(),
+ item.scrollOffset().y / item.pageScaleFactor()));
+ item.setPageScaleFactor(item.pageScaleFactor() /
+ gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()
+ .device_scale_factor());
+ }
+ }
+#endif
+
+ // Subitems
+ int num_children = ReadInteger(obj);
+ for (int i = 0; i < num_children; ++i)
+ item.appendToChildren(ReadHistoryItem(obj,
+ include_form_data,
+ include_scroll_offset,
+ false));
+
+ return item;
+}
+
+// Reconstruct a HistoryItem from a string, using our JSON Value deserializer.
+// This assumes that the given serialized string has all the required key,value
+// pairs, and does minimal error checking. The form data of the post is restored
+// if |include_form_data| is |ALWAYS_INCLUDE_FORM_DATA| or if the data doesn't
+// contain passwords and |include_form_data| is
+// |INCLUDE_FORM_DATA_WITHOUT_PASSWORDS|. Otherwise the form data is empty. If
+// |include_scroll_offset| is true, the scroll offset is restored.
+WebHistoryItem HistoryItemFromString(
+ const std::string& serialized_item,
+ IncludeFormData include_form_data,
+ bool include_scroll_offset) {
+ if (serialized_item.empty())
+ return WebHistoryItem();
+
+ SerializeObject obj(serialized_item.data(),
+ static_cast<int>(serialized_item.length()));
+ return ReadHistoryItem(&obj, include_form_data, include_scroll_offset, true);
+}
+
+void ToFilePathVector(const WebVector<WebString>& input,
+ std::vector<base::FilePath>* output) {
+ for (size_t i = 0; i < input.size(); ++i)
+ output->push_back(webkit_base::WebStringToFilePath(input[i]));
+}
+
+} // namespace
+
+// Serialize a HistoryItem to a string, using our JSON Value serializer.
+std::string HistoryItemToString(const WebHistoryItem& item) {
+ if (item.isNull())
+ return std::string();
+
+ SerializeObject obj;
+ WriteHistoryItem(item, &obj, true);
+ return obj.GetAsString();
+}
+
+WebHistoryItem HistoryItemFromString(const std::string& serialized_item) {
+ return HistoryItemFromString(serialized_item, ALWAYS_INCLUDE_FORM_DATA, true);
+}
+
+std::vector<base::FilePath> FilePathsFromHistoryState(
+ const std::string& content_state) {
+ // TODO(darin): We should avoid using the WebKit API here, so that we do not
+ // need to have WebKit initialized before calling this method.
+
+ std::vector<base::FilePath> result;
+
+ // In newer versions of the format, the set of referenced files is computed
+ // at serialization time.
+ SerializeObject obj(content_state.data(),
+ static_cast<int>(content_state.length()));
+ obj.version = ReadInteger(&obj);
+
+ if (obj.version > kVersion || obj.version < 1)
+ return result;
+
+ if (obj.version >= 14) {
+ ToFilePathVector(ReadStringVector(&obj), &result);
+ } else {
+ // TODO(darin): Delete this code path after we branch for M29.
+ const WebHistoryItem& item =
+ HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, true);
+ if (!item.isNull())
+ ToFilePathVector(item.getReferencedFilePaths(), &result);
+ }
+ return result;
+}
+
+// For testing purposes only.
+void HistoryItemToVersionedString(const WebHistoryItem& item, int version,
+ std::string* serialized_item) {
+ if (item.isNull()) {
+ serialized_item->clear();
+ return;
+ }
+
+ // Temporarily change the version.
+ int real_version = kVersion;
+ kVersion = version;
+
+ SerializeObject obj;
+ WriteHistoryItem(item, &obj, true);
+ *serialized_item = obj.GetAsString();
+
+ kVersion = real_version;
+}
+
+int HistoryItemCurrentVersion() {
+ return kVersion;
+}
+
+std::string RemovePasswordDataFromHistoryState(
+ const std::string& content_state) {
+ // TODO(darin): We should avoid using the WebKit API here, so that we do not
+ // need to have WebKit initialized before calling this method.
+ const WebHistoryItem& item =
+ HistoryItemFromString(
+ content_state, INCLUDE_FORM_DATA_WITHOUT_PASSWORDS, true);
+ if (item.isNull()) {
+ // Couldn't parse the string, return an empty string.
+ return std::string();
+ }
+
+ return HistoryItemToString(item);
+}
+
+std::string RemoveScrollOffsetFromHistoryState(
+ const std::string& content_state) {
+ // TODO(darin): We should avoid using the WebKit API here, so that we do not
+ // need to have WebKit initialized before calling this method.
+ const WebHistoryItem& item =
+ HistoryItemFromString(content_state, ALWAYS_INCLUDE_FORM_DATA, false);
+ if (item.isNull()) {
+ // Couldn't parse the string, return an empty string.
+ return std::string();
+ }
+
+ return HistoryItemToString(item);
+}
+
+std::string CreateHistoryStateForURL(const GURL& url) {
+ // We avoid using the WebKit API here, so that we do not need to have WebKit
+ // initialized before calling this method. Instead, we write a simple
+ // serialization of the given URL with a dummy version number of -1. This
+ // will be interpreted by ReadHistoryItem as a request to create a default
+ // WebHistoryItem.
+ SerializeObject obj;
+ WriteInteger(-1, &obj);
+ WriteGURL(url, &obj);
+ return obj.GetAsString();
+}
+
+} // namespace webkit_glue