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
->pinch_viewport_scroll_offset
= item
.pinchViewportScrollOffset();
93 state
->scroll_offset
= item
.scrollOffset();
94 state
->item_sequence_number
= item
.itemSequenceNumber();
95 state
->document_sequence_number
=
96 item
.documentSequenceNumber();
97 state
->frame_sequence_number
=
98 item
.frameSequenceNumber();
99 state
->page_scale_factor
= item
.pageScaleFactor();
100 ToNullableString16Vector(item
.documentState(), &state
->document_state
);
102 state
->http_body
.http_content_type
= item
.httpContentType();
103 const WebHTTPBody
& http_body
= item
.httpBody();
104 state
->http_body
.is_null
= http_body
.isNull();
105 if (!state
->http_body
.is_null
) {
106 state
->http_body
.identifier
= http_body
.identifier();
107 state
->http_body
.elements
.resize(http_body
.elementCount());
108 for (size_t i
= 0; i
< http_body
.elementCount(); ++i
) {
109 WebHTTPBody::Element element
;
110 http_body
.elementAt(i
, element
);
111 ToExplodedHttpBodyElement(element
, &state
->http_body
.elements
[i
]);
113 state
->http_body
.contains_passwords
= http_body
.containsPasswordData();
117 void RecursivelyGenerateFrameState(
118 HistoryEntry::HistoryNode
* node
,
119 ExplodedFrameState
* state
,
120 std::vector
<base::NullableString16
>* referenced_files
) {
121 GenerateFrameStateFromItem(node
->item(), state
);
122 ToNullableString16Vector(node
->item().getReferencedFilePaths(),
125 std::vector
<HistoryEntry::HistoryNode
*>& children
= node
->children();
126 state
->children
.resize(children
.size());
127 for (size_t i
= 0; i
< children
.size(); ++i
) {
128 RecursivelyGenerateFrameState(children
[i
], &state
->children
[i
],
133 void RecursivelyGenerateHistoryItem(const ExplodedFrameState
& state
,
134 HistoryEntry::HistoryNode
* node
) {
137 item
.setURLString(state
.url_string
);
138 item
.setReferrer(state
.referrer
, state
.referrer_policy
);
139 item
.setTarget(state
.target
);
140 if (!state
.state_object
.is_null()) {
142 WebSerializedScriptValue::fromString(state
.state_object
));
144 item
.setDocumentState(state
.document_state
);
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
);
156 if (state
.frame_sequence_number
)
157 item
.setFrameSequenceNumber(state
.frame_sequence_number
);
159 item
.setHTTPContentType(state
.http_body
.http_content_type
);
160 if (!state
.http_body
.is_null
) {
161 WebHTTPBody http_body
;
162 http_body
.initialize();
163 http_body
.setIdentifier(state
.http_body
.identifier
);
164 for (size_t i
= 0; i
< state
.http_body
.elements
.size(); ++i
)
165 AppendHTTPBodyElement(state
.http_body
.elements
[i
], &http_body
);
166 item
.setHTTPBody(http_body
);
168 node
->set_item(item
);
170 for (size_t i
= 0; i
< state
.children
.size(); ++i
)
171 RecursivelyGenerateHistoryItem(state
.children
[i
], node
->AddChild());
176 PageState
HistoryEntryToPageState(HistoryEntry
* entry
) {
177 ExplodedPageState state
;
178 RecursivelyGenerateFrameState(entry
->root_history_node(), &state
.top
,
179 &state
.referenced_files
);
181 std::string encoded_data
;
182 if (!EncodePageState(state
, &encoded_data
))
185 return PageState::CreateFromEncodedData(encoded_data
);
188 PageState
SingleHistoryItemToPageState(const WebHistoryItem
& item
) {
189 ExplodedPageState state
;
190 ToNullableString16Vector(item
.getReferencedFilePaths(),
191 &state
.referenced_files
);
192 GenerateFrameStateFromItem(item
, &state
.top
);
194 std::string encoded_data
;
195 if (!EncodePageState(state
, &encoded_data
))
198 return PageState::CreateFromEncodedData(encoded_data
);
201 scoped_ptr
<HistoryEntry
> PageStateToHistoryEntry(const PageState
& page_state
) {
202 ExplodedPageState state
;
203 if (!DecodePageState(page_state
.ToEncodedData(), &state
))
204 return scoped_ptr
<HistoryEntry
>();
206 scoped_ptr
<HistoryEntry
> entry(new HistoryEntry());
207 RecursivelyGenerateHistoryItem(state
.top
, entry
->root_history_node());
212 } // namespace content