Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / common / page_state_serialization.cc
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.
4
5 #include "content/common/page_state_serialization.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "base/pickle.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "ui/gfx/screen.h"
15
16 namespace content {
17 namespace {
18
19 #if defined(OS_ANDROID)
20 float g_device_scale_factor_for_testing = 0.0;
21 #endif
22
23 //-----------------------------------------------------------------------------
24
25 void AppendDataToHttpBody(ExplodedHttpBody* http_body, const char* data,
26                           int data_length) {
27   ExplodedHttpBodyElement element;
28   element.type = blink::WebHTTPBody::Element::TypeData;
29   element.data.assign(data, data_length);
30   http_body->elements.push_back(element);
31 }
32
33 void AppendFileRangeToHttpBody(ExplodedHttpBody* http_body,
34                                const base::NullableString16& file_path,
35                                int file_start,
36                                int file_length,
37                                double file_modification_time) {
38   ExplodedHttpBodyElement element;
39   element.type = blink::WebHTTPBody::Element::TypeFile;
40   element.file_path = file_path;
41   element.file_start = file_start;
42   element.file_length = file_length;
43   element.file_modification_time = file_modification_time;
44   http_body->elements.push_back(element);
45 }
46
47 void AppendURLRangeToHttpBody(ExplodedHttpBody* http_body,
48                               const GURL& url,
49                               int file_start,
50                               int file_length,
51                               double file_modification_time) {
52   ExplodedHttpBodyElement element;
53   element.type = blink::WebHTTPBody::Element::TypeFileSystemURL;
54   element.filesystem_url = url;
55   element.file_start = file_start;
56   element.file_length = file_length;
57   element.file_modification_time = file_modification_time;
58   http_body->elements.push_back(element);
59 }
60
61 void AppendBlobToHttpBody(ExplodedHttpBody* http_body,
62                           const std::string& uuid) {
63   ExplodedHttpBodyElement element;
64   element.type = blink::WebHTTPBody::Element::TypeBlob;
65   element.blob_uuid = uuid;
66   http_body->elements.push_back(element);
67 }
68
69 //----------------------------------------------------------------------------
70
71 void AppendReferencedFilesFromHttpBody(
72     const std::vector<ExplodedHttpBodyElement>& elements,
73     std::vector<base::NullableString16>* referenced_files) {
74   for (size_t i = 0; i < elements.size(); ++i) {
75     if (elements[i].type == blink::WebHTTPBody::Element::TypeFile)
76       referenced_files->push_back(elements[i].file_path);
77   }
78 }
79
80 bool AppendReferencedFilesFromDocumentState(
81     const std::vector<base::NullableString16>& document_state,
82     std::vector<base::NullableString16>* referenced_files) {
83   if (document_state.empty())
84     return true;
85
86   // This algorithm is adapted from Blink's core/html/FormController.cpp code.
87   // We only care about how that code worked when this code snapshot was taken
88   // as this code is only needed for backwards compat.
89   //
90   // For reference, see FormController::formStatesFromStateVector at:
91   // http://src.chromium.org/viewvc/blink/trunk/Source/core/html/FormController.cpp?pathrev=152274
92
93   size_t index = 0;
94
95   if (document_state.size() < 3)
96     return false;
97
98   index++;  // Skip over magic signature.
99   index++;  // Skip over form key.
100
101   size_t item_count;
102   if (!base::StringToSizeT(document_state[index++].string(), &item_count))
103     return false;
104
105   while (item_count--) {
106     if (index + 1 >= document_state.size())
107       return false;
108
109     index++;  // Skip over name.
110     const base::NullableString16& type = document_state[index++];
111
112     if (index >= document_state.size())
113       return false;
114
115     size_t value_size;
116     if (!base::StringToSizeT(document_state[index++].string(), &value_size))
117       return false;
118
119     if (index + value_size > document_state.size() ||
120         index + value_size < index)  // Check for overflow.
121       return false;
122
123     if (EqualsASCII(type.string(), "file")) {
124       if (value_size != 2)
125         return false;
126
127       referenced_files->push_back(document_state[index++]);
128       index++;  // Skip over display name.
129     } else {
130       index += value_size;
131     }
132   }
133
134   return true;
135 }
136
137 bool RecursivelyAppendReferencedFiles(
138     const ExplodedFrameState& frame_state,
139     std::vector<base::NullableString16>* referenced_files) {
140   if (!frame_state.http_body.is_null) {
141     AppendReferencedFilesFromHttpBody(frame_state.http_body.elements,
142                                       referenced_files);
143   }
144
145   if (!AppendReferencedFilesFromDocumentState(frame_state.document_state,
146                                               referenced_files))
147     return false;
148
149   for (size_t i = 0; i < frame_state.children.size(); ++i) {
150     if (!RecursivelyAppendReferencedFiles(frame_state.children[i],
151                                           referenced_files))
152       return false;
153   }
154
155   return true;
156 }
157
158 //----------------------------------------------------------------------------
159
160 struct SerializeObject {
161   SerializeObject()
162       : version(0),
163         parse_error(false) {
164   }
165
166   SerializeObject(const char* data, int len)
167       : pickle(data, len),
168         version(0),
169         parse_error(false) {
170     iter = PickleIterator(pickle);
171   }
172
173   std::string GetAsString() {
174     return std::string(static_cast<const char*>(pickle.data()), pickle.size());
175   }
176
177   Pickle pickle;
178   PickleIterator iter;
179   int version;
180   bool parse_error;
181 };
182
183 // Version ID of serialized format.
184 // 11: Min version
185 // 12: Adds support for contains_passwords in HTTP body
186 // 13: Adds support for URL (FileSystem URL)
187 // 14: Adds list of referenced files, version written only for first item.
188 // 15: Removes a bunch of values we defined but never used.
189 // 16: Switched from blob urls to blob uuids.
190 // 17: Add a target frame id number.
191 // 18: Add referrer policy.
192 // 19: Remove target frame id, which was a bad idea, and original url string,
193 //         which is no longer used.
194 // 20: Add pinch viewport scroll offset, the offset of the pinched zoomed
195 //     viewport within the unzoomed main frame.
196 // 21: Add frame sequence number
197 //
198 // NOTE: If the version is -1, then the pickle contains only a URL string.
199 // See ReadPageState.
200 //
201 const int kMinVersion = 11;
202 const int kCurrentVersion = 21;
203
204 // A bunch of convenience functions to read/write to SerializeObjects.  The
205 // de-serializers assume the input data will be in the correct format and fall
206 // back to returning safe defaults when not.
207
208 void WriteData(const void* data, int length, SerializeObject* obj) {
209   obj->pickle.WriteData(static_cast<const char*>(data), length);
210 }
211
212 void ReadData(SerializeObject* obj, const void** data, int* length) {
213   const char* tmp;
214   if (obj->pickle.ReadData(&obj->iter, &tmp, length)) {
215     *data = tmp;
216   } else {
217     obj->parse_error = true;
218     *data = NULL;
219     *length = 0;
220   }
221 }
222
223 void WriteInteger(int data, SerializeObject* obj) {
224   obj->pickle.WriteInt(data);
225 }
226
227 int ReadInteger(SerializeObject* obj) {
228   int tmp;
229   if (obj->pickle.ReadInt(&obj->iter, &tmp))
230     return tmp;
231   obj->parse_error = true;
232   return 0;
233 }
234
235 void ConsumeInteger(SerializeObject* obj) {
236   int unused ALLOW_UNUSED = ReadInteger(obj);
237 }
238
239 void WriteInteger64(int64 data, SerializeObject* obj) {
240   obj->pickle.WriteInt64(data);
241 }
242
243 int64 ReadInteger64(SerializeObject* obj) {
244   int64 tmp = 0;
245   if (obj->pickle.ReadInt64(&obj->iter, &tmp))
246     return tmp;
247   obj->parse_error = true;
248   return 0;
249 }
250
251 void ConsumeInteger64(SerializeObject* obj) {
252   int64 unused ALLOW_UNUSED = ReadInteger64(obj);
253 }
254
255 void WriteReal(double data, SerializeObject* obj) {
256   WriteData(&data, sizeof(double), obj);
257 }
258
259 double ReadReal(SerializeObject* obj) {
260   const void* tmp = NULL;
261   int length = 0;
262   double value = 0.0;
263   ReadData(obj, &tmp, &length);
264   if (length == static_cast<int>(sizeof(double))) {
265     // Use memcpy, as tmp may not be correctly aligned.
266     memcpy(&value, tmp, sizeof(double));
267   } else {
268     obj->parse_error = true;
269   }
270   return value;
271 }
272
273 void ConsumeReal(SerializeObject* obj) {
274   double unused ALLOW_UNUSED = ReadReal(obj);
275 }
276
277 void WriteBoolean(bool data, SerializeObject* obj) {
278   obj->pickle.WriteInt(data ? 1 : 0);
279 }
280
281 bool ReadBoolean(SerializeObject* obj) {
282   bool tmp;
283   if (obj->pickle.ReadBool(&obj->iter, &tmp))
284     return tmp;
285   obj->parse_error = true;
286   return false;
287 }
288
289 void ConsumeBoolean(SerializeObject* obj) {
290   bool unused ALLOW_UNUSED = ReadBoolean(obj);
291 }
292
293 void WriteGURL(const GURL& url, SerializeObject* obj) {
294   obj->pickle.WriteString(url.possibly_invalid_spec());
295 }
296
297 GURL ReadGURL(SerializeObject* obj) {
298   std::string spec;
299   if (obj->pickle.ReadString(&obj->iter, &spec))
300     return GURL(spec);
301   obj->parse_error = true;
302   return GURL();
303 }
304
305 void WriteStdString(const std::string& s, SerializeObject* obj) {
306   obj->pickle.WriteString(s);
307 }
308
309 std::string ReadStdString(SerializeObject* obj) {
310   std::string s;
311   if (obj->pickle.ReadString(&obj->iter, &s))
312     return s;
313   obj->parse_error = true;
314   return std::string();
315 }
316
317 // WriteString pickles the NullableString16 as <int length><char16* data>.
318 // If length == -1, then the NullableString16 itself is null.  Otherwise the
319 // length is the number of char16 (not bytes) in the NullableString16.
320 void WriteString(const base::NullableString16& str, SerializeObject* obj) {
321   if (str.is_null()) {
322     obj->pickle.WriteInt(-1);
323   } else {
324     const base::char16* data = str.string().data();
325     size_t length_in_bytes = str.string().length() * sizeof(base::char16);
326
327     CHECK_LT(length_in_bytes,
328              static_cast<size_t>(std::numeric_limits<int>::max()));
329     obj->pickle.WriteInt(length_in_bytes);
330     obj->pickle.WriteBytes(data, length_in_bytes);
331   }
332 }
333
334 // This reads a serialized NullableString16 from obj. If a string can't be
335 // read, NULL is returned.
336 const base::char16* ReadStringNoCopy(SerializeObject* obj, int* num_chars) {
337   int length_in_bytes;
338   if (!obj->pickle.ReadInt(&obj->iter, &length_in_bytes)) {
339     obj->parse_error = true;
340     return NULL;
341   }
342
343   if (length_in_bytes < 0)
344     return NULL;
345
346   const char* data;
347   if (!obj->pickle.ReadBytes(&obj->iter, &data, length_in_bytes)) {
348     obj->parse_error = true;
349     return NULL;
350   }
351
352   if (num_chars)
353     *num_chars = length_in_bytes / sizeof(base::char16);
354   return reinterpret_cast<const base::char16*>(data);
355 }
356
357 base::NullableString16 ReadString(SerializeObject* obj) {
358   int num_chars;
359   const base::char16* chars = ReadStringNoCopy(obj, &num_chars);
360   return chars ?
361       base::NullableString16(base::string16(chars, num_chars), false) :
362       base::NullableString16();
363 }
364
365 void ConsumeString(SerializeObject* obj) {
366   const base::char16* unused ALLOW_UNUSED = ReadStringNoCopy(obj, NULL);
367 }
368
369 template <typename T>
370 void WriteAndValidateVectorSize(const std::vector<T>& v, SerializeObject* obj) {
371   CHECK_LT(v.size(), std::numeric_limits<int>::max() / sizeof(T));
372   WriteInteger(static_cast<int>(v.size()), obj);
373 }
374
375 size_t ReadAndValidateVectorSize(SerializeObject* obj, size_t element_size) {
376   size_t num_elements = static_cast<size_t>(ReadInteger(obj));
377
378   // Ensure that resizing a vector to size num_elements makes sense.
379   if (std::numeric_limits<int>::max() / element_size <= num_elements) {
380     obj->parse_error = true;
381     return 0;
382   }
383
384   // Ensure that it is plausible for the pickle to contain num_elements worth
385   // of data.
386   if (obj->pickle.payload_size() <= num_elements) {
387     obj->parse_error = true;
388     return 0;
389   }
390
391   return num_elements;
392 }
393
394 // Writes a Vector of strings into a SerializeObject for serialization.
395 void WriteStringVector(
396     const std::vector<base::NullableString16>& data, SerializeObject* obj) {
397   WriteAndValidateVectorSize(data, obj);
398   for (size_t i = 0; i < data.size(); ++i) {
399     WriteString(data[i], obj);
400   }
401 }
402
403 void ReadStringVector(SerializeObject* obj,
404                       std::vector<base::NullableString16>* result) {
405   size_t num_elements =
406       ReadAndValidateVectorSize(obj, sizeof(base::NullableString16));
407
408   result->resize(num_elements);
409   for (size_t i = 0; i < num_elements; ++i)
410     (*result)[i] = ReadString(obj);
411 }
412
413 // Writes an ExplodedHttpBody object into a SerializeObject for serialization.
414 void WriteHttpBody(const ExplodedHttpBody& http_body, SerializeObject* obj) {
415   WriteBoolean(!http_body.is_null, obj);
416
417   if (http_body.is_null)
418     return;
419
420   WriteAndValidateVectorSize(http_body.elements, obj);
421   for (size_t i = 0; i < http_body.elements.size(); ++i) {
422     const ExplodedHttpBodyElement& element = http_body.elements[i];
423     WriteInteger(element.type, obj);
424     if (element.type == blink::WebHTTPBody::Element::TypeData) {
425       WriteData(element.data.data(), static_cast<int>(element.data.size()),
426                 obj);
427     } else if (element.type == blink::WebHTTPBody::Element::TypeFile) {
428       WriteString(element.file_path, obj);
429       WriteInteger64(element.file_start, obj);
430       WriteInteger64(element.file_length, obj);
431       WriteReal(element.file_modification_time, obj);
432     } else if (element.type ==
433                blink::WebHTTPBody::Element::TypeFileSystemURL) {
434       WriteGURL(element.filesystem_url, obj);
435       WriteInteger64(element.file_start, obj);
436       WriteInteger64(element.file_length, obj);
437       WriteReal(element.file_modification_time, obj);
438     } else {
439       DCHECK(element.type == blink::WebHTTPBody::Element::TypeBlob);
440       WriteStdString(element.blob_uuid, obj);
441     }
442   }
443   WriteInteger64(http_body.identifier, obj);
444   WriteBoolean(http_body.contains_passwords, obj);
445 }
446
447 void ReadHttpBody(SerializeObject* obj, ExplodedHttpBody* http_body) {
448   // An initial boolean indicates if we have an HTTP body.
449   if (!ReadBoolean(obj))
450     return;
451   http_body->is_null = false;
452
453   int num_elements = ReadInteger(obj);
454
455   for (int i = 0; i < num_elements; ++i) {
456     int type = ReadInteger(obj);
457     if (type == blink::WebHTTPBody::Element::TypeData) {
458       const void* data;
459       int length = -1;
460       ReadData(obj, &data, &length);
461       if (length >= 0) {
462         AppendDataToHttpBody(http_body, static_cast<const char*>(data),
463                              length);
464       }
465     } else if (type == blink::WebHTTPBody::Element::TypeFile) {
466       base::NullableString16 file_path = ReadString(obj);
467       int64 file_start = ReadInteger64(obj);
468       int64 file_length = ReadInteger64(obj);
469       double file_modification_time = ReadReal(obj);
470       AppendFileRangeToHttpBody(http_body, file_path, file_start, file_length,
471                                 file_modification_time);
472     } else if (type == blink::WebHTTPBody::Element::TypeFileSystemURL) {
473       GURL url = ReadGURL(obj);
474       int64 file_start = ReadInteger64(obj);
475       int64 file_length = ReadInteger64(obj);
476       double file_modification_time = ReadReal(obj);
477       AppendURLRangeToHttpBody(http_body, url, file_start, file_length,
478                                file_modification_time);
479     } else if (type == blink::WebHTTPBody::Element::TypeBlob) {
480       if (obj->version >= 16) {
481         std::string blob_uuid = ReadStdString(obj);
482         AppendBlobToHttpBody(http_body, blob_uuid);
483       } else {
484         ReadGURL(obj); // Skip the obsolete blob url value.
485       }
486     }
487   }
488   http_body->identifier = ReadInteger64(obj);
489
490   if (obj->version >= 12)
491     http_body->contains_passwords = ReadBoolean(obj);
492 }
493
494 // Writes the ExplodedFrameState data into the SerializeObject object for
495 // serialization.
496 void WriteFrameState(
497     const ExplodedFrameState& state, SerializeObject* obj, bool is_top) {
498   // WARNING: This data may be persisted for later use. As such, care must be
499   // taken when changing the serialized format. If a new field needs to be
500   // written, only adding at the end will make it easier to deal with loading
501   // older versions. Similarly, this should NOT save fields with sensitive
502   // data, such as password fields.
503
504   WriteString(state.url_string, obj);
505   WriteString(state.target, obj);
506   WriteInteger(state.scroll_offset.x(), obj);
507   WriteInteger(state.scroll_offset.y(), obj);
508   WriteString(state.referrer, obj);
509
510   WriteStringVector(state.document_state, obj);
511
512   WriteReal(state.page_scale_factor, obj);
513   WriteInteger64(state.item_sequence_number, obj);
514   WriteInteger64(state.document_sequence_number, obj);
515   WriteInteger64(state.frame_sequence_number, obj);
516   WriteInteger(state.referrer_policy, obj);
517   WriteReal(state.pinch_viewport_scroll_offset.x(), obj);
518   WriteReal(state.pinch_viewport_scroll_offset.y(), obj);
519
520   bool has_state_object = !state.state_object.is_null();
521   WriteBoolean(has_state_object, obj);
522   if (has_state_object)
523     WriteString(state.state_object, obj);
524
525   WriteHttpBody(state.http_body, obj);
526
527   // NOTE: It is a quirk of the format that we still have to write the
528   // http_content_type field when the HTTP body is null.  That's why this code
529   // is here instead of inside WriteHttpBody.
530   WriteString(state.http_body.http_content_type, obj);
531
532   // Subitems
533   const std::vector<ExplodedFrameState>& children = state.children;
534   WriteAndValidateVectorSize(children, obj);
535   for (size_t i = 0; i < children.size(); ++i)
536     WriteFrameState(children[i], obj, false);
537 }
538
539 void ReadFrameState(SerializeObject* obj, bool is_top,
540                     ExplodedFrameState* state) {
541   if (obj->version < 14 && !is_top)
542     ConsumeInteger(obj);  // Skip over redundant version field.
543
544   state->url_string = ReadString(obj);
545
546   if (obj->version < 19)
547     ConsumeString(obj);  // Skip obsolete original url string field.
548
549   state->target = ReadString(obj);
550   if (obj->version < 15) {
551     ConsumeString(obj);  // Skip obsolete parent field.
552     ConsumeString(obj);  // Skip obsolete title field.
553     ConsumeString(obj);  // Skip obsolete alternate title field.
554     ConsumeReal(obj);    // Skip obsolete visited time field.
555   }
556
557   int x = ReadInteger(obj);
558   int y = ReadInteger(obj);
559   state->scroll_offset = gfx::Point(x, y);
560
561   if (obj->version < 15) {
562     ConsumeBoolean(obj);  // Skip obsolete target item flag.
563     ConsumeInteger(obj);  // Skip obsolete visit count field.
564   }
565   state->referrer = ReadString(obj);
566
567   ReadStringVector(obj, &state->document_state);
568
569   state->page_scale_factor = ReadReal(obj);
570   state->item_sequence_number = ReadInteger64(obj);
571   state->document_sequence_number = ReadInteger64(obj);
572   if (obj->version >= 21)
573     state->frame_sequence_number = ReadInteger64(obj);
574
575   if (obj->version >= 17 && obj->version < 19)
576     ConsumeInteger64(obj); // Skip obsolete target frame id number.
577
578   if (obj->version >= 18) {
579     state->referrer_policy =
580         static_cast<blink::WebReferrerPolicy>(ReadInteger(obj));
581   }
582
583   if (obj->version >= 20) {
584     double x = ReadReal(obj);
585     double y = ReadReal(obj);
586     state->pinch_viewport_scroll_offset = gfx::PointF(x, y);
587   } else {
588     state->pinch_viewport_scroll_offset = gfx::PointF(-1, -1);
589   }
590
591   bool has_state_object = ReadBoolean(obj);
592   if (has_state_object)
593     state->state_object = ReadString(obj);
594
595   ReadHttpBody(obj, &state->http_body);
596
597   // NOTE: It is a quirk of the format that we still have to read the
598   // http_content_type field when the HTTP body is null.  That's why this code
599   // is here instead of inside ReadHttpBody.
600   state->http_body.http_content_type = ReadString(obj);
601
602   if (obj->version < 14)
603     ConsumeString(obj);  // Skip unused referrer string.
604
605 #if defined(OS_ANDROID)
606   if (obj->version == 11) {
607     // Now-unused values that shipped in this version of Chrome for Android when
608     // it was on a private branch.
609     ReadReal(obj);
610     ReadBoolean(obj);
611
612     // In this version, page_scale_factor included device_scale_factor and
613     // scroll offsets were premultiplied by pageScaleFactor.
614     if (state->page_scale_factor) {
615       float device_scale_factor = g_device_scale_factor_for_testing;
616       if (!device_scale_factor) {
617         device_scale_factor =
618             gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().
619                 device_scale_factor();
620       }
621       state->scroll_offset =
622           gfx::Point(state->scroll_offset.x() / state->page_scale_factor,
623                      state->scroll_offset.y() / state->page_scale_factor);
624       state->page_scale_factor /= device_scale_factor;
625     }
626   }
627 #endif
628
629   // Subitems
630   size_t num_children =
631       ReadAndValidateVectorSize(obj, sizeof(ExplodedFrameState));
632   state->children.resize(num_children);
633   for (size_t i = 0; i < num_children; ++i)
634     ReadFrameState(obj, false, &state->children[i]);
635 }
636
637 void WritePageState(const ExplodedPageState& state, SerializeObject* obj) {
638   WriteInteger(obj->version, obj);
639   WriteStringVector(state.referenced_files, obj);
640   WriteFrameState(state.top, obj, true);
641 }
642
643 void ReadPageState(SerializeObject* obj, ExplodedPageState* state) {
644   obj->version = ReadInteger(obj);
645
646   if (obj->version == -1) {
647     GURL url = ReadGURL(obj);
648     // NOTE: GURL::possibly_invalid_spec() always returns valid UTF-8.
649     state->top.url_string =
650         base::NullableString16(
651             base::UTF8ToUTF16(url.possibly_invalid_spec()), false);
652     return;
653   }
654
655   if (obj->version > kCurrentVersion || obj->version < kMinVersion) {
656     obj->parse_error = true;
657     return;
658   }
659
660   if (obj->version >= 14)
661     ReadStringVector(obj, &state->referenced_files);
662
663   ReadFrameState(obj, true, &state->top);
664
665   if (obj->version < 14)
666     RecursivelyAppendReferencedFiles(state->top, &state->referenced_files);
667
668   // De-dupe
669   state->referenced_files.erase(
670       std::unique(state->referenced_files.begin(),
671                   state->referenced_files.end()),
672       state->referenced_files.end());
673 }
674
675 }  // namespace
676
677 ExplodedHttpBodyElement::ExplodedHttpBodyElement()
678     : type(blink::WebHTTPBody::Element::TypeData),
679       file_start(0),
680       file_length(-1),
681       file_modification_time(std::numeric_limits<double>::quiet_NaN()) {
682 }
683
684 ExplodedHttpBodyElement::~ExplodedHttpBodyElement() {
685 }
686
687 ExplodedHttpBody::ExplodedHttpBody()
688     : identifier(0),
689       contains_passwords(false),
690       is_null(true) {
691 }
692
693 ExplodedHttpBody::~ExplodedHttpBody() {
694 }
695
696 ExplodedFrameState::ExplodedFrameState()
697     : item_sequence_number(0),
698       document_sequence_number(0),
699       frame_sequence_number(0),
700       page_scale_factor(0.0),
701       referrer_policy(blink::WebReferrerPolicyDefault) {
702 }
703
704 ExplodedFrameState::ExplodedFrameState(const ExplodedFrameState& other) {
705   assign(other);
706 }
707
708 ExplodedFrameState::~ExplodedFrameState() {
709 }
710
711 void ExplodedFrameState::operator=(const ExplodedFrameState& other) {
712   if (&other != this)
713     assign(other);
714 }
715
716 void ExplodedFrameState::assign(const ExplodedFrameState& other) {
717   url_string = other.url_string;
718   referrer = other.referrer;
719   target = other.target;
720   state_object = other.state_object;
721   document_state = other.document_state;
722   pinch_viewport_scroll_offset = other.pinch_viewport_scroll_offset;
723   scroll_offset = other.scroll_offset;
724   item_sequence_number = other.item_sequence_number;
725   document_sequence_number = other.document_sequence_number;
726   frame_sequence_number = other.frame_sequence_number;
727   page_scale_factor = other.page_scale_factor;
728   referrer_policy = other.referrer_policy;
729   http_body = other.http_body;
730   children = other.children;
731 }
732
733 ExplodedPageState::ExplodedPageState() {
734 }
735
736 ExplodedPageState::~ExplodedPageState() {
737 }
738
739 bool DecodePageState(const std::string& encoded, ExplodedPageState* exploded) {
740   *exploded = ExplodedPageState();
741
742   if (encoded.empty())
743     return true;
744
745   SerializeObject obj(encoded.data(), static_cast<int>(encoded.size()));
746   ReadPageState(&obj, exploded);
747   return !obj.parse_error;
748 }
749
750 bool EncodePageState(const ExplodedPageState& exploded, std::string* encoded) {
751   SerializeObject obj;
752   obj.version = kCurrentVersion;
753   WritePageState(exploded, &obj);
754   *encoded = obj.GetAsString();
755   return true;
756 }
757
758 #if defined(OS_ANDROID)
759 bool DecodePageStateWithDeviceScaleFactorForTesting(
760     const std::string& encoded,
761     float device_scale_factor,
762     ExplodedPageState* exploded) {
763   g_device_scale_factor_for_testing = device_scale_factor;
764   bool rv = DecodePageState(encoded, exploded);
765   g_device_scale_factor_for_testing = 0.0;
766   return rv;
767 }
768 #endif
769
770 }  // namespace content