diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-26 02:02:18 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-26 02:02:18 +0000 |
commit | e0185f9fe7ba991f701ac7bb6d8dbafa745a31ab (patch) | |
tree | d43a5f87c837ba410e30e0d9095f1cd3e1a9c95c /webkit/glue/glue_serialize.cc | |
parent | d70d82db35eecb586629a05bffc580282c0c30b4 (diff) | |
download | chromium_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.cc | 668 |
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 |