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

Unified Diff: content/common/page_state_serialization.cc

Issue 16867005: Re-implement PageState serialization without a Blink API dependency. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improvements based on Tom's feedback. Created 7 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/page_state_serialization.h ('k') | content/common/page_state_serialization_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/page_state_serialization.cc
diff --git a/webkit/glue/glue_serialize_deprecated.cc b/content/common/page_state_serialization.cc
similarity index 18%
rename from webkit/glue/glue_serialize_deprecated.cc
rename to content/common/page_state_serialization.cc
index 62d4c8984f289a7ac0670d77d8ccd614b560d87a..c44175fa92721be2e379c333a542a66354733aa6 100644
--- a/webkit/glue/glue_serialize_deprecated.cc
+++ b/content/common/page_state_serialization.cc
@@ -1,120 +1,224 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 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_deprecated.h"
+#include "content/common/page_state_serialization.h"
-#include <string>
+#include <algorithm>
+#include <limits>
#include "base/pickle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebHTTPBody.h"
-#include "third_party/WebKit/public/platform/WebPoint.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/WebKit/public/web/WebHistoryItem.h"
-#include "third_party/WebKit/public/web/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 content {
+namespace {
-namespace webkit_glue {
+//-----------------------------------------------------------------------------
+
+void AppendDataToHttpBody(ExplodedHttpBody* http_body, const char* data,
+ int data_length) {
+ ExplodedHttpBodyElement element;
+ element.type = WebKit::WebHTTPBody::Element::TypeData;
+ element.data.assign(data, data_length);
+ http_body->elements.push_back(element);
+}
+
+void AppendFileRangeToHttpBody(ExplodedHttpBody* http_body,
+ const base::NullableString16& file_path,
+ int file_start,
+ int file_length,
+ double file_modification_time) {
+ ExplodedHttpBodyElement element;
+ element.type = WebKit::WebHTTPBody::Element::TypeFile;
+ element.file_path = file_path;
+ element.file_start = file_start;
+ element.file_length = file_length;
+ element.file_modification_time = file_modification_time;
+ http_body->elements.push_back(element);
+}
+
+void AppendURLRangeToHttpBody(ExplodedHttpBody* http_body,
+ const GURL& url,
+ int file_start,
+ int file_length,
+ double file_modification_time) {
+ ExplodedHttpBodyElement element;
+ element.type = WebKit::WebHTTPBody::Element::TypeURL;
+ element.url = url;
+ element.file_start = file_start;
+ element.file_length = file_length;
+ element.file_modification_time = file_modification_time;
+ http_body->elements.push_back(element);
+}
+
+void AppendBlobToHttpBody(ExplodedHttpBody* http_body, const GURL& url) {
+ ExplodedHttpBodyElement element;
+ element.type = WebKit::WebHTTPBody::Element::TypeBlob;
+ element.url = url;
+ http_body->elements.push_back(element);
+}
+
+//----------------------------------------------------------------------------
+
+void AppendReferencedFilesFromHttpBody(
+ const std::vector<ExplodedHttpBodyElement>& elements,
+ std::vector<base::NullableString16>* referenced_files) {
+ for (size_t i = 0; i < elements.size(); ++i) {
+ if (elements[i].type == WebKit::WebHTTPBody::Element::TypeFile)
+ referenced_files->push_back(elements[i].file_path);
+ }
+}
-namespace {
+bool AppendReferencedFilesFromDocumentState(
+ const std::vector<base::NullableString16>& document_state,
+ std::vector<base::NullableString16>* referenced_files) {
+ if (document_state.empty())
+ return true;
-enum IncludeFormData {
- NEVER_INCLUDE_FORM_DATA,
- INCLUDE_FORM_DATA_WITHOUT_PASSWORDS,
- ALWAYS_INCLUDE_FORM_DATA
-};
+ // This algorithm is adapted from Blink's core/html/FormController.cpp code.
+ // We only care about how that code worked when this code snapshot was taken
+ // as this code is only needed for backwards compat.
+ //
+ // For reference, see FormController::formStatesFromStateVector at:
+ // http://src.chromium.org/viewvc/blink/trunk/Source/core/html/FormController.cpp?pathrev=152274
+
+ size_t index = 0;
+
+ if (document_state.size() < 3)
+ return false;
+
+ index++; // Skip over magic signature.
+ index++; // Skip over form key.
+
+ size_t item_count;
+ if (!base::StringToSizeT(document_state[index++].string(), &item_count))
+ return false;
+
+ while (item_count--) {
+ if (index + 1 >= document_state.size())
+ return false;
+
+ index++; // Skip over name.
+ const base::NullableString16& type = document_state[index++];
+
+ if (index >= document_state.size())
+ return false;
+
+ size_t value_size;
+ if (!base::StringToSizeT(document_state[index++].string(), &value_size))
+ return false;
+
+ if (index + value_size > document_state.size() ||
+ index + value_size < index) // Check for overflow.
+ return false;
+
+ if (EqualsASCII(type.string(), "file")) {
+ if (value_size != 2)
+ return false;
+
+ referenced_files->push_back(document_state[index++]);
+ index++; // Skip over display name.
+ } else {
+ index += value_size;
+ }
+ }
+
+ return true;
+}
+
+bool RecursivelyAppendReferencedFiles(
+ const ExplodedFrameState& frame_state,
+ std::vector<base::NullableString16>* referenced_files) {
+ if (!frame_state.http_body.is_null) {
+ AppendReferencedFilesFromHttpBody(frame_state.http_body.elements,
+ referenced_files);
+ }
+
+ if (!AppendReferencedFilesFromDocumentState(frame_state.document_state,
+ referenced_files))
+ return false;
+
+ for (size_t i = 0; i < frame_state.children.size(); ++i) {
+ if (!RecursivelyAppendReferencedFiles(frame_state.children[i],
+ referenced_files))
+ return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
struct SerializeObject {
- SerializeObject() : version(0) {}
+ SerializeObject()
+ : version(0),
+ parse_error(false) {
+ }
+
SerializeObject(const char* data, int len)
- : pickle(data, len), version(0) { iter = PickleIterator(pickle); }
+ : pickle(data, len),
+ version(0),
+ parse_error(false) {
+ 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;
+ PickleIterator iter;
+ int version;
+ bool parse_error;
};
-// 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
+// Version ID of serialized format.
+// 11: Min version
+// 12: Adds support for contains_passwords 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.
+// See ReadPageState.
//
-int kVersion = 14;
+const int kMinVersion = 11;
+const int kCurrentVersion = 14;
+
+// A bunch of convenience functions to read/write to SerializeObjects. The
+// de-serializers assume the input data will be in the correct format and fall
+// back to returning safe defaults when not.
-// 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) {
+void ReadData(SerializeObject* obj, const void** data, int* length) {
const char* tmp;
if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
*data = tmp;
} else {
+ obj->parse_error = true;
*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 ReadInteger(SerializeObject* obj) {
int tmp;
if (obj->pickle.ReadInt(&obj->iter, &tmp))
return tmp;
+ obj->parse_error = true;
return 0;
}
-void ConsumeInteger(const SerializeObject* obj) {
+void ConsumeInteger(SerializeObject* obj) {
int unused ALLOW_UNUSED = ReadInteger(obj);
}
@@ -122,24 +226,28 @@ void WriteInteger64(int64 data, SerializeObject* obj) {
obj->pickle.WriteInt64(data);
}
-int64 ReadInteger64(const SerializeObject* obj) {
+int64 ReadInteger64(SerializeObject* obj) {
int64 tmp = 0;
- obj->pickle.ReadInt64(&obj->iter, &tmp);
- return tmp;
+ if (obj->pickle.ReadInt64(&obj->iter, &tmp))
+ return tmp;
+ obj->parse_error = true;
+ return 0;
}
void WriteReal(double data, SerializeObject* obj) {
WriteData(&data, sizeof(double), obj);
}
-double ReadReal(const SerializeObject* obj) {
+double ReadReal(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))) {
+ if (length == static_cast<int>(sizeof(double))) {
// Use memcpy, as tmp may not be correctly aligned.
memcpy(&value, tmp, sizeof(double));
+ } else {
+ obj->parse_error = true;
}
return value;
}
@@ -148,10 +256,11 @@ void WriteBoolean(bool data, SerializeObject* obj) {
obj->pickle.WriteInt(data ? 1 : 0);
}
-bool ReadBoolean(const SerializeObject* obj) {
+bool ReadBoolean(SerializeObject* obj) {
bool tmp;
if (obj->pickle.ReadBool(&obj->iter, &tmp))
return tmp;
+ obj->parse_error = true;
return false;
}
@@ -159,349 +268,274 @@ void WriteGURL(const GURL& url, SerializeObject* obj) {
obj->pickle.WriteString(url.possibly_invalid_spec());
}
-GURL ReadGURL(const SerializeObject* obj) {
+GURL ReadGURL(SerializeObject* obj) {
std::string spec;
if (obj->pickle.ReadString(&obj->iter, &spec))
return GURL(spec);
+ obj->parse_error = true;
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) {
- base::string16 string = str;
- const char16* data = string.data();
- size_t length_in_uchars = string.length();
- size_t length_in_bytes = length_in_uchars * sizeof(char16);
- switch (kVersion) {
- case 1:
- // Version 1 writes <length in bytes><string data>.
- // It saves WebString() and "" as "".
- obj->pickle.WriteInt(length_in_bytes);
- obj->pickle.WriteBytes(data, length_in_bytes);
- 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(length_in_uchars);
- obj->pickle.WriteBytes(data, length_in_bytes);
- }
- 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(length_in_bytes);
- obj->pickle.WriteBytes(data, length_in_bytes);
- }
- break;
+// WriteString pickles the NullableString16 as <int length><char16* data>.
+// If length == -1, then the NullableString16 itself is null. Otherwise the
+// length is the number of char16 (not bytes) in the NullableString16.
+void WriteString(const base::NullableString16& str, SerializeObject* obj) {
+ if (str.is_null()) {
+ obj->pickle.WriteInt(-1);
+ } else {
+ const char16* data = str.string().data();
+ size_t length_in_bytes = str.string().length() * sizeof(char16);
+
+ CHECK_LT(length_in_bytes,
+ static_cast<size_t>(std::numeric_limits<int>::max()));
+ obj->pickle.WriteInt(length_in_bytes);
+ obj->pickle.WriteBytes(data, length_in_bytes);
}
}
-// 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))
+// This reads a serialized NullableString16 from obj. If a string can't be
+// read, NULL is returned.
+const char16* ReadStringNoCopy(SerializeObject* obj, int* num_chars) {
+ int length_in_bytes;
+ if (!obj->pickle.ReadInt(&obj->iter, &length_in_bytes)) {
+ obj->parse_error = true;
return NULL;
+ }
- // Starting with version 2, -1 means WebString().
- if (length == -1)
+ if (length_in_bytes < 0)
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))
+ const char* data;
+ if (!obj->pickle.ReadBytes(&obj->iter, &data, length_in_bytes)) {
+ obj->parse_error = true;
return NULL;
+ }
if (num_chars)
- *num_chars = bytes / sizeof(WebUChar);
- return static_cast<const WebUChar*>(data);
+ *num_chars = length_in_bytes / sizeof(char16);
+ return reinterpret_cast<const char16*>(data);
}
-WebString ReadString(const SerializeObject* obj) {
+base::NullableString16 ReadString(SerializeObject* obj) {
int num_chars;
- const WebUChar* chars = ReadStringNoCopy(obj, &num_chars);
- return chars ? WebString(chars, num_chars) : WebString();
+ const char16* chars = ReadStringNoCopy(obj, &num_chars);
+ return chars ?
+ base::NullableString16(base::string16(chars, num_chars), false) :
+ base::NullableString16();
}
-void ConsumeString(const SerializeObject* obj) {
- const WebUChar* unused ALLOW_UNUSED = ReadStringNoCopy(obj, NULL);
+void ConsumeString(SerializeObject* obj) {
+ const char16* 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);
+template <typename T>
+void WriteAndValidateVectorSize(const std::vector<T>& v, SerializeObject* obj) {
+ CHECK_LT(v.size(), std::numeric_limits<int>::max() / sizeof(T));
+ WriteInteger(static_cast<int>(v.size()), obj);
+}
+
+size_t ReadAndValidateVectorSize(SerializeObject* obj, size_t element_size) {
+ size_t num_elements = static_cast<size_t>(ReadInteger(obj));
+
+ // Ensure that resizing a vector to size num_elements makes sense.
+ if (std::numeric_limits<int>::max() / element_size <= num_elements) {
+ obj->parse_error = true;
+ return 0;
+ }
+
+ // Ensure that it is plausible for the pickle to contain num_elements worth
+ // of data.
+ if (obj->pickle.payload_size() <= num_elements) {
+ obj->parse_error = true;
+ return 0;
}
+
+ return num_elements;
}
-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;
+// Writes a Vector of strings into a SerializeObject for serialization.
+void WriteStringVector(
+ const std::vector<base::NullableString16>& data, SerializeObject* obj) {
+ WriteAndValidateVectorSize(data, obj);
+ for (size_t i = 0; i < data.size(); ++i) {
+ WriteString(data[i], obj);
+ }
}
-void ConsumeStringVector(const SerializeObject* obj) {
- int num_elements = ReadInteger(obj);
- for (int i = 0; i < num_elements; ++i)
- ConsumeString(obj);
+void ReadStringVector(SerializeObject* obj,
+ std::vector<base::NullableString16>* result) {
+ size_t num_elements =
+ ReadAndValidateVectorSize(obj, sizeof(base::NullableString16));
+
+ result->resize(num_elements);
+ for (size_t i = 0; i < num_elements; ++i)
+ (*result)[i] = ReadString(obj);
}
-// Writes a FormData object into a SerializeObject for serialization.
-void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
- WriteBoolean(!http_body.isNull(), obj);
+// Writes an ExplodedHttpBody object into a SerializeObject for serialization.
+void WriteHttpBody(const ExplodedHttpBody& http_body, SerializeObject* obj) {
+ WriteBoolean(!http_body.is_null, obj);
- if (http_body.isNull())
+ if (http_body.is_null)
return;
- WriteInteger(static_cast<int>(http_body.elementCount()), obj);
- WebHTTPBody::Element element;
- for (size_t i = 0; http_body.elementAt(i, element); ++i) {
+ WriteAndValidateVectorSize(http_body.elements, obj);
+ for (size_t i = 0; i < http_body.elements.size(); ++i) {
+ const ExplodedHttpBodyElement& element = http_body.elements[i];
WriteInteger(element.type, obj);
- if (element.type == WebHTTPBody::Element::TypeData) {
+ if (element.type == WebKit::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) {
+ } else if (element.type == WebKit::WebHTTPBody::Element::TypeFile) {
+ WriteString(element.file_path, obj);
+ WriteInteger64(element.file_start, obj);
+ WriteInteger64(element.file_length, obj);
+ WriteReal(element.file_modification_time, obj);
+ } else if (element.type == WebKit::WebHTTPBody::Element::TypeURL) {
WriteGURL(element.url, obj);
- WriteInteger64(element.fileStart, obj);
- WriteInteger64(element.fileLength, obj);
- WriteReal(element.modificationTime, obj);
+ WriteInteger64(element.file_start, obj);
+ WriteInteger64(element.file_length, obj);
+ WriteReal(element.file_modification_time, obj);
} else {
WriteGURL(element.url, obj);
}
}
- WriteInteger64(http_body.identifier(), obj);
- WriteBoolean(http_body.containsPasswordData(), obj);
+ WriteInteger64(http_body.identifier, obj);
+ WriteBoolean(http_body.contains_passwords, 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();
+void ReadHttpBody(SerializeObject* obj, ExplodedHttpBody* http_body) {
+ // An initial boolean indicates if we have an HTTP body.
+ if (!ReadBoolean(obj))
+ return;
+ http_body->is_null = false;
- // 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) {
+ if (type == WebKit::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);
+ if (length >= 0) {
+ AppendDataToHttpBody(http_body, static_cast<const char*>(data),
+ length);
}
- http_body.appendFileRange(file_path, file_start, file_length,
- modification_time);
- } else if (type == WebHTTPBody::Element::TypeURL) {
+ } else if (type == WebKit::WebHTTPBody::Element::TypeFile) {
+ base::NullableString16 file_path = ReadString(obj);
+ int64 file_start = ReadInteger64(obj);
+ int64 file_length = ReadInteger64(obj);
+ double file_modification_time = ReadReal(obj);
+ AppendFileRangeToHttpBody(http_body, file_path, file_start, file_length,
+ file_modification_time);
+ } else if (type == WebKit::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) {
+ int64 file_start = ReadInteger64(obj);
+ int64 file_length = ReadInteger64(obj);
+ double file_modification_time = ReadReal(obj);
+ AppendURLRangeToHttpBody(http_body, url, file_start, file_length,
+ file_modification_time);
+ } else if (type == WebKit::WebHTTPBody::Element::TypeBlob) {
GURL blob_url = ReadGURL(obj);
- http_body.appendBlob(blob_url);
+ AppendBlobToHttpBody(http_body, blob_url);
}
}
- if (obj->version >= 4)
- http_body.setIdentifier(ReadInteger64(obj));
+ http_body->identifier = ReadInteger64(obj);
if (obj->version >= 12)
- http_body.setContainsPasswordData(ReadBoolean(obj));
-
- return http_body;
+ http_body->contains_passwords = ReadBoolean(obj);
}
-// Writes the HistoryItem data into the SerializeObject object for
+// Writes the ExplodedFrameState data into the SerializeObject object for
// serialization.
-void WriteHistoryItem(
- const WebHistoryItem& item, SerializeObject* obj, bool is_top) {
+void WriteFrameState(
+ const ExplodedFrameState& state, 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);
+ WriteString(state.url_string, obj);
+ WriteString(state.original_url_string, obj);
+ WriteString(state.target, obj);
+ WriteString(state.parent, obj);
+ WriteString(state.title, obj);
+ WriteString(state.alternate_title, obj);
+ WriteReal(state.visited_time, obj);
+ WriteInteger(state.scroll_offset.x(), obj);
+ WriteInteger(state.scroll_offset.y(), obj);
+ WriteBoolean(state.is_target_item, obj);
+ WriteInteger(state.visit_count, obj);
+ WriteString(state.referrer, obj);
+
+ WriteStringVector(state.document_state, obj);
+
+ WriteReal(state.page_scale_factor, obj);
+ WriteInteger64(state.item_sequence_number, obj);
+ WriteInteger64(state.document_sequence_number, obj);
+
+ bool has_state_object = !state.state_object.is_null();
+ WriteBoolean(has_state_object, obj);
+ if (has_state_object)
+ WriteString(state.state_object, obj);
+
+ WriteHttpBody(state.http_body, obj);
+
+ // NOTE: It is a quirk of the format that we still have to write the
+ // http_content_type field when the HTTP body is null. That's why this code
+ // is here instead of inside WriteHttpBody.
+ WriteString(state.http_body.http_content_type, 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);
- }
+ // Subitems
+ const std::vector<ExplodedFrameState>& children = state.children;
+ WriteAndValidateVectorSize(children, obj);
+ for (size_t i = 0; i < children.size(); ++i)
+ WriteFrameState(children[i], obj, false);
+}
- 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);
- }
+void ReadFrameState(SerializeObject* obj, bool is_top,
+ ExplodedFrameState* state) {
+ if (obj->version < 14 && !is_top)
+ ConsumeInteger(obj); // Skip over redundant version field.
- WriteFormData(item.httpBody(), obj);
- WriteString(item.httpContentType(), obj);
- if (kVersion < 14)
- WriteString(item.referrer(), obj);
+ state->url_string = ReadString(obj);
+ state->original_url_string = ReadString(obj);
+ state->target = ReadString(obj);
+ state->parent = ReadString(obj);
+ state->title = ReadString(obj);
+ state->alternate_title = ReadString(obj);
+ state->visited_time = ReadReal(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;
- }
+ int x = ReadInteger(obj);
+ int y = ReadInteger(obj);
+ state->scroll_offset = gfx::Point(x, y);
- if (obj->version > kVersion || obj->version < 1)
- return WebHistoryItem();
+ state->is_target_item = ReadBoolean(obj);
+ state->visit_count = ReadInteger(obj);
+ state->referrer = ReadString(obj);
- if (obj->version >= 14)
- ConsumeStringVector(obj); // Skip over list of referenced files.
- } else if (obj->version < 14) {
- ConsumeInteger(obj); // Skip over redundant version field.
- }
+ ReadStringVector(obj, &state->document_state);
- WebHistoryItem item;
- item.initialize();
+ state->page_scale_factor = ReadReal(obj);
+ state->item_sequence_number = ReadInteger64(obj);
+ state->document_sequence_number = ReadInteger64(obj);
- 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));
+ bool has_state_object = ReadBoolean(obj);
+ if (has_state_object)
+ state->state_object = ReadString(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)));
- }
- }
+ ReadHttpBody(obj, &state->http_body);
- // The extra referrer string is read for backwards compat.
- const WebHTTPBody& http_body = ReadFormData(obj);
- const WebString& http_content_type = ReadString(obj);
+ // NOTE: It is a quirk of the format that we still have to read the
+ // http_content_type field when the HTTP body is null. That's why this code
+ // is here instead of inside ReadHttpBody.
+ state->http_body.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
@@ -509,14 +543,13 @@ WebHistoryItem ReadHistoryItem(
ReadReal(obj);
ReadBoolean(obj);
- // In this version, pageScaleFactor included deviceScaleFactor and scroll
+ // In this version, page_scale_factor 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() /
+ if (state->page_scale_factor) {
+ state->scroll_offset =
+ gfx::Point(state->scroll_offset.x() / state->page_scale_factor,
+ state->scroll_offset.y() / state->page_scale_factor);
+ state->page_scale_factor = (state->page_scale_factor /
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()
.device_scale_factor());
}
@@ -524,147 +557,106 @@ WebHistoryItem ReadHistoryItem(
#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);
+ size_t num_children =
+ ReadAndValidateVectorSize(obj, sizeof(ExplodedFrameState));
+ state->children.resize(num_children);
+ for (size_t i = 0; i < num_children; ++i)
+ ReadFrameState(obj, false, &state->children[i]);
}
-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]));
+void WritePageState(const ExplodedPageState& state, SerializeObject* obj) {
+ WriteInteger(obj->version, obj);
+ WriteStringVector(state.referenced_files, obj);
+ WriteFrameState(state.top, obj, true);
}
-} // namespace
+void ReadPageState(SerializeObject* obj, ExplodedPageState* state) {
+ obj->version = ReadInteger(obj);
-// Serialize a HistoryItem to a string, using our JSON Value serializer.
-std::string HistoryItemToString(const WebHistoryItem& item) {
- if (item.isNull())
- return std::string();
+ if (obj->version == -1) {
+ GURL url = ReadGURL(obj);
+ // NOTE: GURL::possibly_invalid_spec() always returns valid UTF-8.
+ state->top.url_string = state->top.original_url_string =
+ base::NullableString16(UTF8ToUTF16(url.possibly_invalid_spec()), false);
+ return;
+ }
- SerializeObject obj;
- WriteHistoryItem(item, &obj, true);
- return obj.GetAsString();
-}
+ if (obj->version > kCurrentVersion || obj->version < kMinVersion) {
+ obj->parse_error = true;
+ return;
+ }
-WebHistoryItem HistoryItemFromString(const std::string& serialized_item) {
- return HistoryItemFromString(serialized_item, ALWAYS_INCLUDE_FORM_DATA, true);
-}
+ if (obj->version >= 14)
+ ReadStringVector(obj, &state->referenced_files);
-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.
+ ReadFrameState(obj, true, &state->top);
- std::vector<base::FilePath> result;
+ if (obj->version < 14)
+ RecursivelyAppendReferencedFiles(state->top, &state->referenced_files);
- // 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);
+ // De-dupe
+ state->referenced_files.erase(
+ std::unique(state->referenced_files.begin(),
+ state->referenced_files.end()),
+ state->referenced_files.end());
+}
- if (obj.version > kVersion || obj.version < 1)
- return result;
+} // namespace
- 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;
+ExplodedHttpBodyElement::ExplodedHttpBodyElement()
+ : type(WebKit::WebHTTPBody::Element::TypeData),
+ file_start(0),
+ file_length(-1),
+ file_modification_time(std::numeric_limits<double>::quiet_NaN()) {
}
-// For testing purposes only.
-void HistoryItemToVersionedString(const WebHistoryItem& item, int version,
- std::string* serialized_item) {
- if (item.isNull()) {
- serialized_item->clear();
- return;
- }
+ExplodedHttpBodyElement::~ExplodedHttpBodyElement() {
+}
- // Temporarily change the version.
- int real_version = kVersion;
- kVersion = version;
+ExplodedHttpBody::ExplodedHttpBody()
+ : identifier(0),
+ contains_passwords(false),
+ is_null(true) {
+}
- SerializeObject obj;
- WriteHistoryItem(item, &obj, true);
- *serialized_item = obj.GetAsString();
+ExplodedHttpBody::~ExplodedHttpBody() {
+}
- kVersion = real_version;
+ExplodedFrameState::ExplodedFrameState()
+ : item_sequence_number(0),
+ document_sequence_number(0),
+ visit_count(0),
+ visited_time(0.0),
+ page_scale_factor(0.0),
+ is_target_item(false) {
}
-int HistoryItemCurrentVersion() {
- return kVersion;
+ExplodedFrameState::~ExplodedFrameState() {
}
-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();
- }
+ExplodedPageState::ExplodedPageState() {
+}
- return HistoryItemToString(item);
+ExplodedPageState::~ExplodedPageState() {
}
-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();
- }
+bool DecodePageState(const std::string& encoded, ExplodedPageState* exploded) {
+ *exploded = ExplodedPageState();
+
+ if (encoded.empty())
+ return true;
- return HistoryItemToString(item);
+ SerializeObject obj(encoded.data(), static_cast<int>(encoded.size()));
+ ReadPageState(&obj, exploded);
+ return !obj.parse_error;
}
-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.
+bool EncodePageState(const ExplodedPageState& exploded, std::string* encoded) {
SerializeObject obj;
- WriteInteger(-1, &obj);
- WriteGURL(url, &obj);
- return obj.GetAsString();
+ obj.version = kCurrentVersion;
+ WritePageState(exploded, &obj);
+ *encoded = obj.GetAsString();
+ return true;
}
-} // namespace webkit_glue
+} // namespace content
« no previous file with comments | « content/common/page_state_serialization.h ('k') | content/common/page_state_serialization_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698