1 // Copyright 2014 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 "content/renderer/history_serialization.h"
7 #include "content/common/page_state_serialization.h"
8 #include "content/public/common/page_state.h"
9 #include "content/renderer/history_entry.h"
10 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
11 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
12 #include "third_party/WebKit/public/platform/WebPoint.h"
13 #include "third_party/WebKit/public/platform/WebString.h"
14 #include "third_party/WebKit/public/platform/WebVector.h"
15 #include "third_party/WebKit/public/web/WebHistoryItem.h"
16 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
18 using blink::WebHTTPBody
;
19 using blink::WebHistoryItem
;
20 using blink::WebSerializedScriptValue
;
21 using blink::WebString
;
22 using blink::WebVector
;
27 void ToNullableString16Vector(const WebVector
<WebString
>& input
,
28 std::vector
<base::NullableString16
>* output
) {
29 output
->reserve(output
->size() + input
.size());
30 for (size_t i
= 0; i
< input
.size(); ++i
)
31 output
->push_back(input
[i
]);
34 void ToExplodedHttpBodyElement(const WebHTTPBody::Element
& input
,
35 ExplodedHttpBodyElement
* output
) {
37 case WebHTTPBody::Element::TypeData
:
38 output
->data
.assign(input
.data
.data(), input
.data
.size());
40 case WebHTTPBody::Element::TypeFile
:
41 output
->file_path
= input
.filePath
;
42 output
->file_start
= input
.fileStart
;
43 output
->file_length
= input
.fileLength
;
44 output
->file_modification_time
= input
.modificationTime
;
46 case WebHTTPBody::Element::TypeFileSystemURL
:
47 output
->filesystem_url
= input
.fileSystemURL
;
48 output
->file_start
= input
.fileStart
;
49 output
->file_length
= input
.fileLength
;
50 output
->file_modification_time
= input
.modificationTime
;
52 case WebHTTPBody::Element::TypeBlob
:
53 output
->blob_uuid
= input
.blobUUID
.utf8();
58 void AppendHTTPBodyElement(const ExplodedHttpBodyElement
& element
,
59 WebHTTPBody
* http_body
) {
60 switch (element
.type
) {
61 case WebHTTPBody::Element::TypeData
:
62 http_body
->appendData(element
.data
);
64 case WebHTTPBody::Element::TypeFile
:
65 http_body
->appendFileRange(
69 element
.file_modification_time
);
71 case WebHTTPBody::Element::TypeFileSystemURL
:
72 http_body
->appendFileSystemURLRange(
73 element
.filesystem_url
,
76 element
.file_modification_time
);
78 case WebHTTPBody::Element::TypeBlob
:
79 http_body
->appendBlob(WebString::fromUTF8(element
.blob_uuid
));
84 void GenerateFrameStateFromItem(const WebHistoryItem
& item
,
85 ExplodedFrameState
* state
) {
86 state
->url_string
= item
.urlString();
87 state
->referrer
= item
.referrer();
88 state
->referrer_policy
= item
.referrerPolicy();
89 state
->target
= item
.target();
90 if (!item
.stateObject().isNull())
91 state
->state_object
= item
.stateObject().toString();
92 state
->scroll_restoration_type
= item
.scrollRestorationType();
93 state
->pinch_viewport_scroll_offset
= item
.pinchViewportScrollOffset();
94 state
->scroll_offset
= item
.scrollOffset();
95 state
->item_sequence_number
= item
.itemSequenceNumber();
96 state
->document_sequence_number
=
97 item
.documentSequenceNumber();
98 state
->page_scale_factor
= item
.pageScaleFactor();
99 ToNullableString16Vector(item
.documentState(), &state
->document_state
);
101 state
->http_body
.http_content_type
= item
.httpContentType();
102 const WebHTTPBody
& http_body
= item
.httpBody();
103 state
->http_body
.is_null
= http_body
.isNull();
104 if (!state
->http_body
.is_null
) {
105 state
->http_body
.identifier
= http_body
.identifier();
106 state
->http_body
.elements
.resize(http_body
.elementCount());
107 for (size_t i
= 0; i
< http_body
.elementCount(); ++i
) {
108 WebHTTPBody::Element element
;
109 http_body
.elementAt(i
, element
);
110 ToExplodedHttpBodyElement(element
, &state
->http_body
.elements
[i
]);
112 state
->http_body
.contains_passwords
= http_body
.containsPasswordData();
116 void RecursivelyGenerateFrameState(
117 HistoryEntry::HistoryNode
* node
,
118 ExplodedFrameState
* state
,
119 std::vector
<base::NullableString16
>* referenced_files
) {
120 GenerateFrameStateFromItem(node
->item(), state
);
121 ToNullableString16Vector(node
->item().getReferencedFilePaths(),
124 std::vector
<HistoryEntry::HistoryNode
*>& children
= node
->children();
125 state
->children
.resize(children
.size());
126 for (size_t i
= 0; i
< children
.size(); ++i
) {
127 RecursivelyGenerateFrameState(children
[i
], &state
->children
[i
],
132 void RecursivelyGenerateHistoryItem(const ExplodedFrameState
& state
,
133 HistoryEntry::HistoryNode
* node
) {
136 item
.setURLString(state
.url_string
);
137 item
.setReferrer(state
.referrer
, state
.referrer_policy
);
138 item
.setTarget(state
.target
);
139 if (!state
.state_object
.is_null()) {
141 WebSerializedScriptValue::fromString(state
.state_object
));
143 item
.setDocumentState(state
.document_state
);
144 item
.setScrollRestorationType(state
.scroll_restoration_type
);
145 item
.setPinchViewportScrollOffset(state
.pinch_viewport_scroll_offset
);
146 item
.setScrollOffset(state
.scroll_offset
);
147 item
.setPageScaleFactor(state
.page_scale_factor
);
149 // These values are generated at WebHistoryItem construction time, and we
150 // only want to override those new values with old values if the old values
151 // are defined. A value of 0 means undefined in this context.
152 if (state
.item_sequence_number
)
153 item
.setItemSequenceNumber(state
.item_sequence_number
);
154 if (state
.document_sequence_number
)
155 item
.setDocumentSequenceNumber(state
.document_sequence_number
);
157 item
.setHTTPContentType(state
.http_body
.http_content_type
);
158 if (!state
.http_body
.is_null
) {
159 WebHTTPBody http_body
;
160 http_body
.initialize();
161 http_body
.setIdentifier(state
.http_body
.identifier
);
162 for (size_t i
= 0; i
< state
.http_body
.elements
.size(); ++i
)
163 AppendHTTPBodyElement(state
.http_body
.elements
[i
], &http_body
);
164 item
.setHTTPBody(http_body
);
166 node
->set_item(item
);
168 for (size_t i
= 0; i
< state
.children
.size(); ++i
)
169 RecursivelyGenerateHistoryItem(state
.children
[i
], node
->AddChild());
174 PageState
HistoryEntryToPageState(HistoryEntry
* entry
) {
175 ExplodedPageState state
;
176 RecursivelyGenerateFrameState(entry
->root_history_node(), &state
.top
,
177 &state
.referenced_files
);
179 std::string encoded_data
;
180 if (!EncodePageState(state
, &encoded_data
))
183 return PageState::CreateFromEncodedData(encoded_data
);
186 PageState
SingleHistoryItemToPageState(const WebHistoryItem
& item
) {
187 ExplodedPageState state
;
188 ToNullableString16Vector(item
.getReferencedFilePaths(),
189 &state
.referenced_files
);
190 GenerateFrameStateFromItem(item
, &state
.top
);
192 std::string encoded_data
;
193 if (!EncodePageState(state
, &encoded_data
))
196 return PageState::CreateFromEncodedData(encoded_data
);
199 scoped_ptr
<HistoryEntry
> PageStateToHistoryEntry(const PageState
& page_state
) {
200 ExplodedPageState state
;
201 if (!DecodePageState(page_state
.ToEncodedData(), &state
))
202 return scoped_ptr
<HistoryEntry
>();
204 scoped_ptr
<HistoryEntry
> entry(new HistoryEntry());
205 RecursivelyGenerateHistoryItem(state
.top
, entry
->root_history_node());
210 } // namespace content