1 // Copyright 2013 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.
7 #include "base/base64.h"
8 #include "base/files/file_util.h"
9 #include "base/path_service.h"
10 #include "base/pickle.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/common/page_state_serialization.h"
15 #include "content/public/common/content_paths.h"
16 #include "testing/gtest/include/gtest/gtest.h"
21 base::NullableString16
NS16(const char* s
) {
22 return s
? base::NullableString16(base::ASCIIToUTF16(s
), false) :
23 base::NullableString16();
26 //-----------------------------------------------------------------------------
29 void ExpectEquality(const T
& a
, const T
& b
) {
34 void ExpectEquality(const std::vector
<T
>& a
, const std::vector
<T
>& b
) {
35 EXPECT_EQ(a
.size(), b
.size());
36 for (size_t i
= 0; i
< std::min(a
.size(), b
.size()); ++i
)
37 ExpectEquality(a
[i
], b
[i
]);
41 void ExpectEquality(const ExplodedHttpBodyElement
& a
,
42 const ExplodedHttpBodyElement
& b
) {
43 EXPECT_EQ(a
.type
, b
.type
);
44 EXPECT_EQ(a
.data
, b
.data
);
45 EXPECT_EQ(a
.file_path
, b
.file_path
);
46 EXPECT_EQ(a
.filesystem_url
, b
.filesystem_url
);
47 EXPECT_EQ(a
.file_start
, b
.file_start
);
48 EXPECT_EQ(a
.file_length
, b
.file_length
);
49 if (!(std::isnan(a
.file_modification_time
) &&
50 std::isnan(b
.file_modification_time
))) {
51 EXPECT_DOUBLE_EQ(a
.file_modification_time
, b
.file_modification_time
);
53 EXPECT_EQ(a
.blob_uuid
, b
.blob_uuid
);
57 void ExpectEquality(const ExplodedHttpBody
& a
, const ExplodedHttpBody
& b
) {
58 EXPECT_EQ(a
.http_content_type
, b
.http_content_type
);
59 EXPECT_EQ(a
.identifier
, b
.identifier
);
60 EXPECT_EQ(a
.contains_passwords
, b
.contains_passwords
);
61 EXPECT_EQ(a
.is_null
, b
.is_null
);
62 ExpectEquality(a
.elements
, b
.elements
);
66 void ExpectEquality(const ExplodedFrameState
& a
, const ExplodedFrameState
& b
) {
67 EXPECT_EQ(a
.url_string
, b
.url_string
);
68 EXPECT_EQ(a
.referrer
, b
.referrer
);
69 EXPECT_EQ(a
.referrer_policy
, b
.referrer_policy
);
70 EXPECT_EQ(a
.target
, b
.target
);
71 EXPECT_EQ(a
.state_object
, b
.state_object
);
72 ExpectEquality(a
.document_state
, b
.document_state
);
73 EXPECT_EQ(a
.scroll_restoration_type
, b
.scroll_restoration_type
);
74 EXPECT_EQ(a
.pinch_viewport_scroll_offset
, b
.pinch_viewport_scroll_offset
);
75 EXPECT_EQ(a
.scroll_offset
, b
.scroll_offset
);
76 EXPECT_EQ(a
.item_sequence_number
, b
.item_sequence_number
);
77 EXPECT_EQ(a
.document_sequence_number
, b
.document_sequence_number
);
78 EXPECT_EQ(a
.page_scale_factor
, b
.page_scale_factor
);
79 ExpectEquality(a
.http_body
, b
.http_body
);
80 ExpectEquality(a
.children
, b
.children
);
83 void ExpectEquality(const ExplodedPageState
& a
, const ExplodedPageState
& b
) {
84 ExpectEquality(a
.referenced_files
, b
.referenced_files
);
85 ExpectEquality(a
.top
, b
.top
);
88 //-----------------------------------------------------------------------------
90 class PageStateSerializationTest
: public testing::Test
{
92 void PopulateFrameState(ExplodedFrameState
* frame_state
) {
93 // Invent some data for the various fields.
94 frame_state
->url_string
= NS16("http://dev.chromium.org/");
95 frame_state
->referrer
= NS16("https://www.google.com/search?q=dev.chromium.org");
96 frame_state
->referrer_policy
= blink::WebReferrerPolicyAlways
;
97 frame_state
->target
= NS16("foo");
98 frame_state
->state_object
= NS16(NULL
);
99 frame_state
->document_state
.push_back(NS16("1"));
100 frame_state
->document_state
.push_back(NS16("q"));
101 frame_state
->document_state
.push_back(NS16("text"));
102 frame_state
->document_state
.push_back(NS16("dev.chromium.org"));
103 frame_state
->scroll_restoration_type
=
104 blink::WebHistoryScrollRestorationManual
;
105 frame_state
->pinch_viewport_scroll_offset
= gfx::PointF(10, 15);
106 frame_state
->scroll_offset
= gfx::Point(0, 100);
107 frame_state
->item_sequence_number
= 1;
108 frame_state
->document_sequence_number
= 2;
109 frame_state
->page_scale_factor
= 2.0;
112 void PopulateHttpBody(ExplodedHttpBody
* http_body
,
113 std::vector
<base::NullableString16
>* referenced_files
) {
114 http_body
->is_null
= false;
115 http_body
->identifier
= 12345;
116 http_body
->contains_passwords
= false;
117 http_body
->http_content_type
= NS16("text/foo");
119 ExplodedHttpBodyElement e1
;
120 e1
.type
= blink::WebHTTPBody::Element::TypeData
;
122 http_body
->elements
.push_back(e1
);
124 ExplodedHttpBodyElement e2
;
125 e2
.type
= blink::WebHTTPBody::Element::TypeFile
;
126 e2
.file_path
= NS16("file.txt");
128 e2
.file_length
= 1024;
129 e2
.file_modification_time
= 9999.0;
130 http_body
->elements
.push_back(e2
);
132 referenced_files
->push_back(e2
.file_path
);
135 void PopulateFrameStateForBackwardsCompatTest(
136 ExplodedFrameState
* frame_state
,
138 frame_state
->url_string
= NS16("http://chromium.org/");
139 frame_state
->referrer
= NS16("http://google.com/");
140 frame_state
->referrer_policy
= blink::WebReferrerPolicyDefault
;
142 frame_state
->target
= NS16("target");
143 frame_state
->scroll_restoration_type
=
144 blink::WebHistoryScrollRestorationAuto
;
145 frame_state
->pinch_viewport_scroll_offset
= gfx::PointF(-1, -1);
146 frame_state
->scroll_offset
= gfx::Point(42, -42);
147 frame_state
->item_sequence_number
= 123;
148 frame_state
->document_sequence_number
= 456;
149 frame_state
->page_scale_factor
= 2.0f
;
151 frame_state
->document_state
.push_back(
152 NS16("\n\r?% WebKit serialized form state version 8 \n\r=&"));
153 frame_state
->document_state
.push_back(NS16("form key"));
154 frame_state
->document_state
.push_back(NS16("1"));
155 frame_state
->document_state
.push_back(NS16("foo"));
156 frame_state
->document_state
.push_back(NS16("file"));
157 frame_state
->document_state
.push_back(NS16("2"));
158 frame_state
->document_state
.push_back(NS16("file.txt"));
159 frame_state
->document_state
.push_back(NS16("displayName"));
162 frame_state
->http_body
.http_content_type
= NS16("foo/bar");
163 frame_state
->http_body
.identifier
= 789;
164 frame_state
->http_body
.is_null
= false;
166 ExplodedHttpBodyElement e1
;
167 e1
.type
= blink::WebHTTPBody::Element::TypeData
;
168 e1
.data
= "first data block";
169 frame_state
->http_body
.elements
.push_back(e1
);
171 ExplodedHttpBodyElement e2
;
172 e2
.type
= blink::WebHTTPBody::Element::TypeFile
;
173 e2
.file_path
= NS16("file.txt");
174 frame_state
->http_body
.elements
.push_back(e2
);
176 ExplodedHttpBodyElement e3
;
177 e3
.type
= blink::WebHTTPBody::Element::TypeData
;
178 e3
.data
= "data the second";
179 frame_state
->http_body
.elements
.push_back(e3
);
181 ExplodedFrameState child_state
;
182 PopulateFrameStateForBackwardsCompatTest(&child_state
, true);
183 frame_state
->children
.push_back(child_state
);
187 void PopulatePageStateForBackwardsCompatTest(ExplodedPageState
* page_state
) {
188 page_state
->referenced_files
.push_back(NS16("file.txt"));
189 PopulateFrameStateForBackwardsCompatTest(&page_state
->top
, false);
192 void TestBackwardsCompat(int version
) {
193 const char* suffix
= "";
195 #if defined(OS_ANDROID)
196 // Unfortunately, the format of version 11 is different on Android, so we
197 // need to use a special reference file.
203 PathService::Get(content::DIR_TEST_DATA
, &path
);
204 path
= path
.AppendASCII("page_state").AppendASCII(
205 base::StringPrintf("serialized_v%d%s.dat", version
, suffix
));
207 std::string file_contents
;
208 if (!base::ReadFileToString(path
, &file_contents
)) {
209 ADD_FAILURE() << "File not found: " << path
.value();
213 std::string trimmed_contents
;
214 EXPECT_TRUE(base::RemoveChars(file_contents
, "\r\n", &trimmed_contents
));
217 EXPECT_TRUE(base::Base64Decode(trimmed_contents
, &encoded
));
219 ExplodedPageState output
;
220 #if defined(OS_ANDROID)
221 // Because version 11 of the file format unfortunately bakes in the device
222 // scale factor on Android, perform this test by assuming a preset device
223 // scale factor, ignoring the device scale factor of the current device.
224 const float kPresetDeviceScaleFactor
= 2.0f
;
225 EXPECT_TRUE(DecodePageStateWithDeviceScaleFactorForTesting(
227 kPresetDeviceScaleFactor
,
230 EXPECT_TRUE(DecodePageState(encoded
, &output
));
233 ExplodedPageState expected
;
234 PopulatePageStateForBackwardsCompatTest(&expected
);
236 ExpectEquality(expected
, output
);
240 TEST_F(PageStateSerializationTest
, BasicEmpty
) {
241 ExplodedPageState input
;
244 EXPECT_TRUE(EncodePageState(input
, &encoded
));
246 ExplodedPageState output
;
247 EXPECT_TRUE(DecodePageState(encoded
, &output
));
249 ExpectEquality(input
, output
);
252 TEST_F(PageStateSerializationTest
, BasicFrame
) {
253 ExplodedPageState input
;
254 PopulateFrameState(&input
.top
);
257 EXPECT_TRUE(EncodePageState(input
, &encoded
));
259 ExplodedPageState output
;
260 EXPECT_TRUE(DecodePageState(encoded
, &output
));
262 ExpectEquality(input
, output
);
265 TEST_F(PageStateSerializationTest
, BasicFramePOST
) {
266 ExplodedPageState input
;
267 PopulateFrameState(&input
.top
);
268 PopulateHttpBody(&input
.top
.http_body
, &input
.referenced_files
);
271 EXPECT_TRUE(EncodePageState(input
, &encoded
));
273 ExplodedPageState output
;
274 EXPECT_TRUE(DecodePageState(encoded
, &output
));
276 ExpectEquality(input
, output
);
279 TEST_F(PageStateSerializationTest
, BasicFrameSet
) {
280 ExplodedPageState input
;
281 PopulateFrameState(&input
.top
);
283 // Add some child frames.
284 for (int i
= 0; i
< 4; ++i
) {
285 ExplodedFrameState child_state
;
286 PopulateFrameState(&child_state
);
287 input
.top
.children
.push_back(child_state
);
291 EXPECT_TRUE(EncodePageState(input
, &encoded
));
293 ExplodedPageState output
;
294 EXPECT_TRUE(DecodePageState(encoded
, &output
));
296 ExpectEquality(input
, output
);
299 TEST_F(PageStateSerializationTest
, BasicFrameSetPOST
) {
300 ExplodedPageState input
;
301 PopulateFrameState(&input
.top
);
303 // Add some child frames.
304 for (int i
= 0; i
< 4; ++i
) {
305 ExplodedFrameState child_state
;
306 PopulateFrameState(&child_state
);
308 // Simulate a form POST on a subframe.
310 PopulateHttpBody(&child_state
.http_body
, &input
.referenced_files
);
312 input
.top
.children
.push_back(child_state
);
316 EncodePageState(input
, &encoded
);
318 ExplodedPageState output
;
319 DecodePageState(encoded
, &output
);
321 ExpectEquality(input
, output
);
324 TEST_F(PageStateSerializationTest
, BadMessagesTest1
) {
329 for (int i
= 0; i
< 6; ++i
)
334 std::string
s(static_cast<const char*>(p
.data()), p
.size());
336 ExplodedPageState output
;
337 EXPECT_FALSE(DecodePageState(s
, &output
));
340 TEST_F(PageStateSerializationTest
, BadMessagesTest2
) {
346 for (int i
= 0; i
< 6; ++i
)
349 p
.WriteData(reinterpret_cast<const char*>(&d
), sizeof(d
));
358 p
.WriteInt(blink::WebHTTPBody::Element::TypeData
);
360 std::string
s(static_cast<const char*>(p
.data()), p
.size());
362 ExplodedPageState output
;
363 EXPECT_FALSE(DecodePageState(s
, &output
));
366 TEST_F(PageStateSerializationTest
, DumpExpectedPageStateForBackwardsCompat
) {
367 // Change to #if 1 to enable this code. Use this code to generate data, based
368 // on the current serialization format, for the BackwardsCompat_vXX tests.
370 ExplodedPageState state
;
371 PopulatePageStateForBackwardsCompatTest(&state
);
374 EXPECT_TRUE(EncodePageState(state
, &encoded
));
377 base::Base64Encode(encoded
, &base64
);
380 PathService::Get(base::DIR_TEMP
, &path
);
381 path
= path
.AppendASCII("expected.dat");
383 FILE* fp
= base::OpenFile(path
, "wb");
386 const size_t kRowSize
= 76;
387 for (size_t offset
= 0; offset
< base64
.size(); offset
+= kRowSize
) {
388 size_t length
= std::min(base64
.size() - offset
, kRowSize
);
389 std::string
segment(&base64
[offset
], length
);
390 segment
.push_back('\n');
391 ASSERT_EQ(1U, fwrite(segment
.data(), segment
.size(), 1, fp
));
398 #if !defined(OS_ANDROID)
399 // TODO(darin): Re-enable for Android once this test accounts for systems with
400 // a device scale factor not equal to 2.
401 TEST_F(PageStateSerializationTest
, BackwardsCompat_v11
) {
402 TestBackwardsCompat(11);
406 TEST_F(PageStateSerializationTest
, BackwardsCompat_v12
) {
407 TestBackwardsCompat(12);
410 TEST_F(PageStateSerializationTest
, BackwardsCompat_v13
) {
411 TestBackwardsCompat(13);
414 TEST_F(PageStateSerializationTest
, BackwardsCompat_v14
) {
415 TestBackwardsCompat(14);
418 TEST_F(PageStateSerializationTest
, BackwardsCompat_v15
) {
419 TestBackwardsCompat(15);
422 TEST_F(PageStateSerializationTest
, BackwardsCompat_v16
) {
423 TestBackwardsCompat(16);
426 TEST_F(PageStateSerializationTest
, BackwardsCompat_v18
) {
427 TestBackwardsCompat(18);
430 TEST_F(PageStateSerializationTest
, BackwardsCompat_v20
) {
431 TestBackwardsCompat(20);
434 TEST_F(PageStateSerializationTest
, BackwardsCompat_v21
) {
435 TestBackwardsCompat(21);
438 TEST_F(PageStateSerializationTest
, BackwardsCompat_v22
) {
439 TestBackwardsCompat(22);
443 } // namespace content