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(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(HistoryEntry::HistoryNode
* node
,
118 ExplodedFrameState
* state
) {
119 GenerateFrameStateFromItem(node
->item(), state
);
121 std::vector
<HistoryEntry::HistoryNode
*>& children
= node
->children();
122 state
->children
.resize(children
.size());
123 for (size_t i
= 0; i
< children
.size(); ++i
)
124 RecursivelyGenerateFrameState(children
[i
], &state
->children
[i
]);
127 void RecursivelyGenerateHistoryItem(const ExplodedFrameState
& state
,
128 HistoryEntry::HistoryNode
* node
) {
131 item
.setURLString(state
.url_string
);
132 item
.setReferrer(state
.referrer
, state
.referrer_policy
);
133 item
.setTarget(state
.target
);
134 if (!state
.state_object
.is_null()) {
136 WebSerializedScriptValue::fromString(state
.state_object
));
138 item
.setDocumentState(state
.document_state
);
139 item
.setPinchViewportScrollOffset(state
.pinch_viewport_scroll_offset
);
140 item
.setScrollOffset(state
.scroll_offset
);
141 item
.setPageScaleFactor(state
.page_scale_factor
);
143 // These values are generated at WebHistoryItem construction time, and we
144 // only want to override those new values with old values if the old values
145 // are defined. A value of 0 means undefined in this context.
146 if (state
.item_sequence_number
)
147 item
.setItemSequenceNumber(state
.item_sequence_number
);
148 if (state
.document_sequence_number
)
149 item
.setDocumentSequenceNumber(state
.document_sequence_number
);
150 if (state
.frame_sequence_number
)
151 item
.setFrameSequenceNumber(state
.frame_sequence_number
);
153 item
.setHTTPContentType(state
.http_body
.http_content_type
);
154 if (!state
.http_body
.is_null
) {
155 WebHTTPBody http_body
;
156 http_body
.initialize();
157 http_body
.setIdentifier(state
.http_body
.identifier
);
158 for (size_t i
= 0; i
< state
.http_body
.elements
.size(); ++i
)
159 AppendHTTPBodyElement(state
.http_body
.elements
[i
], &http_body
);
160 item
.setHTTPBody(http_body
);
162 node
->set_item(item
);
164 for (size_t i
= 0; i
< state
.children
.size(); ++i
)
165 RecursivelyGenerateHistoryItem(state
.children
[i
], node
->AddChild());
170 PageState
HistoryEntryToPageState(HistoryEntry
* entry
) {
171 ExplodedPageState state
;
172 ToNullableString16Vector(entry
->root().getReferencedFilePaths(),
173 &state
.referenced_files
);
175 RecursivelyGenerateFrameState(entry
->root_history_node(), &state
.top
);
177 std::string encoded_data
;
178 if (!EncodePageState(state
, &encoded_data
))
181 return PageState::CreateFromEncodedData(encoded_data
);
184 PageState
SingleHistoryItemToPageState(const WebHistoryItem
& item
) {
185 ExplodedPageState state
;
186 ToNullableString16Vector(item
.getReferencedFilePaths(),
187 &state
.referenced_files
);
188 GenerateFrameStateFromItem(item
, &state
.top
);
190 std::string encoded_data
;
191 if (!EncodePageState(state
, &encoded_data
))
194 return PageState::CreateFromEncodedData(encoded_data
);
197 scoped_ptr
<HistoryEntry
> PageStateToHistoryEntry(const PageState
& page_state
) {
198 ExplodedPageState state
;
199 if (!DecodePageState(page_state
.ToEncodedData(), &state
))
200 return scoped_ptr
<HistoryEntry
>();
202 scoped_ptr
<HistoryEntry
> entry(new HistoryEntry());
203 RecursivelyGenerateHistoryItem(state
.top
, entry
->root_history_node());
208 } // namespace content