Begin work on decoding form data
[WebKit-https.git] / Source / WebKit2 / UIProcess / mac / LegacySessionStateCoding.cpp
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "LegacySessionStateCoding.h"
28
29 #include "APIData.h"
30 #include "SessionState.h"
31 #include <wtf/cf/TypeCasts.h>
32
33 namespace WebKit {
34
35 // Session state keys.
36 static const uint32_t sessionStateDataVersion = 2;
37
38 static const CFStringRef sessionHistoryKey = CFSTR("SessionHistory");
39 static const CFStringRef provisionalURLKey = CFSTR("ProvisionalURL");
40
41 // Session history keys.
42 static const CFStringRef sessionHistoryVersionKey = CFSTR("SessionHistoryVersion");
43 static const CFStringRef sessionHistoryCurrentIndexKey = CFSTR("SessionHistoryCurrentIndex");
44 static const CFStringRef sessionHistoryEntriesKey = CFSTR("SessionHistoryEntries");
45
46 // Session history entry keys.
47 static const CFStringRef sessionHistoryEntryURLKey = CFSTR("SessionHistoryEntryURL");
48 static CFStringRef sessionHistoryEntryTitleKey = CFSTR("SessionHistoryEntryTitle");
49 static CFStringRef sessionHistoryEntryOriginalURLKey = CFSTR("SessionHistoryEntryOriginalURL");
50 static CFStringRef sessionHistoryEntrySnapshotUUIDKey = CFSTR("SessionHistoryEntrySnapshotUUID");
51 static CFStringRef sessionHistoryEntryDataKey = CFSTR("SessionHistoryEntryData");
52
53 // Session history entry data.
54 const uint32_t sessionHistoryEntryDataVersion = 2;
55
56 LegacySessionStateDecoder::LegacySessionStateDecoder(API::Data* data)
57     : m_data(data)
58 {
59 }
60
61 LegacySessionStateDecoder::~LegacySessionStateDecoder()
62 {
63 }
64
65 bool LegacySessionStateDecoder::decodeSessionState(SessionState& sessionState) const
66 {
67     if (!m_data)
68         return false;
69
70     size_t size = m_data->size();
71     const uint8_t* bytes = m_data->bytes();
72
73     if (size < sizeof(uint32_t))
74         return false;
75
76     uint32_t versionNumber = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
77
78     if (versionNumber != sessionStateDataVersion)
79         return false;
80
81     auto data = adoptCF(CFDataCreate(kCFAllocatorDefault, bytes + sizeof(uint32_t), size - sizeof(uint32_t)));
82
83     auto sessionStateDictionary = adoptCF(dynamic_cf_cast<CFDictionaryRef>(CFPropertyListCreateWithData(kCFAllocatorDefault, data.get(), kCFPropertyListImmutable, nullptr, nullptr)));
84     if (!sessionStateDictionary)
85         return false;
86
87     if (auto backForwardListDictionary = dynamic_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(sessionStateDictionary.get(), sessionHistoryKey))) {
88         if (!decodeSessionHistory(backForwardListDictionary, sessionState.backForwardListState))
89             return false;
90     }
91
92     if (auto provisionalURLString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(sessionStateDictionary.get(), provisionalURLKey))) {
93         sessionState.provisionalURL = WebCore::URL(WebCore::URL(), provisionalURLString);
94         if (!sessionState.provisionalURL.isValid())
95             return false;
96     }
97
98     return true;
99 }
100
101 bool LegacySessionStateDecoder::decodeSessionHistory(CFDictionaryRef backForwardListDictionary, BackForwardListState& backForwardListState) const
102 {
103     auto sessionHistoryVersionNumber = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(backForwardListDictionary, sessionHistoryVersionKey));
104     if (!sessionHistoryVersionNumber) {
105         // Version 0 session history dictionaries did not contain a version number.
106         return decodeV0SessionHistory(backForwardListDictionary, backForwardListState);
107     }
108
109     CFIndex sessionHistoryVersion;
110     if (!CFNumberGetValue(sessionHistoryVersionNumber, kCFNumberCFIndexType, &sessionHistoryVersion))
111         return false;
112
113     if (sessionHistoryVersion == 1)
114         return decodeV1SessionHistory(backForwardListDictionary, backForwardListState);
115
116     return false;
117 }
118
119 bool LegacySessionStateDecoder::decodeV0SessionHistory(CFDictionaryRef sessionHistoryDictionary, BackForwardListState& backForwardListState) const
120 {
121     // FIXME: Implement.
122     return false;
123 }
124
125 bool LegacySessionStateDecoder::decodeV1SessionHistory(CFDictionaryRef sessionHistoryDictionary, BackForwardListState& backForwardListState) const
126 {
127     auto currentIndexNumber = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryCurrentIndexKey));
128     if (!currentIndexNumber) {
129         // No current index means the dictionary represents an empty session.
130         backForwardListState.currentIndex = 0;
131         backForwardListState.items = { };
132         return true;
133     }
134
135     CFIndex currentIndex;
136     if (!CFNumberGetValue(currentIndexNumber, kCFNumberCFIndexType, &currentIndex))
137         return false;
138
139     if (currentIndex < 0)
140         return false;
141
142     auto historyEntries = dynamic_cf_cast<CFArrayRef>(CFDictionaryGetValue(sessionHistoryDictionary, sessionHistoryEntriesKey));
143     if (!historyEntries)
144         return false;
145
146     if (!decodeSessionHistoryEntries(historyEntries, backForwardListState.items))
147         return false;
148
149     backForwardListState.currentIndex = static_cast<uint32_t>(currentIndex);
150     if (backForwardListState.currentIndex >= backForwardListState.items.size())
151         return false;
152
153     return true;
154 }
155
156 bool LegacySessionStateDecoder::decodeSessionHistoryEntries(CFArrayRef entriesArray, Vector<PageState>& entries) const
157 {
158     for (CFIndex i = 0, size = CFArrayGetCount(entriesArray); i < size; ++i) {
159         auto entryDictionary = dynamic_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(entriesArray, i));
160         if (!entryDictionary)
161             return false;
162
163         PageState entry;
164         if (!decodeSessionHistoryEntry(entryDictionary, entry))
165             return false;
166
167         entries.append(std::move(entry));
168     }
169
170     return true;
171 }
172
173 bool LegacySessionStateDecoder::decodeSessionHistoryEntry(CFDictionaryRef entryDictionary, PageState& pageState) const
174 {
175     auto title = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryTitleKey));
176     if (!title)
177         return false;
178
179     auto urlString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryURLKey));
180     if (!urlString)
181         return false;
182
183     auto originalURLString = dynamic_cf_cast<CFStringRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryOriginalURLKey));
184     if (!originalURLString)
185         return false;
186
187     auto historyEntryData = dynamic_cf_cast<CFDataRef>(CFDictionaryGetValue(entryDictionary, sessionHistoryEntryDataKey));
188     if (!historyEntryData)
189         return false;
190
191     if (!decodeSessionHistoryEntryData(historyEntryData, pageState.mainFrameState))
192         return false;
193
194     pageState.title = title;
195     pageState.mainFrameState.urlString = urlString;
196     pageState.mainFrameState.originalURLString = originalURLString;
197
198     return true;
199 }
200
201 template<typename T> void isValidEnum(T);
202
203 class HistoryEntryDataDecoder {
204 public:
205     HistoryEntryDataDecoder(const uint8_t* buffer, size_t bufferSize)
206         : m_buffer(buffer)
207         , m_bufferEnd(buffer + bufferSize)
208     {
209         // Keep format compatibility by decoding an unused uint64_t here.
210         uint64_t value;
211         *this >> value;
212     }
213
214     HistoryEntryDataDecoder& operator>>(bool& value)
215     {
216         return decodeArithmeticType(value);
217     }
218
219     HistoryEntryDataDecoder& operator>>(uint32_t& value)
220     {
221         return decodeArithmeticType(value);
222     }
223
224     HistoryEntryDataDecoder& operator>>(int32_t& value)
225     {
226         return *this >> reinterpret_cast<uint32_t&>(value);
227     }
228
229     HistoryEntryDataDecoder& operator>>(uint64_t& value)
230     {
231         return decodeArithmeticType(value);
232     }
233
234     HistoryEntryDataDecoder& operator>>(int64_t& value)
235     {
236         return *this >> reinterpret_cast<uint64_t&>(value);
237     }
238
239     HistoryEntryDataDecoder& operator>>(float& value)
240     {
241         return decodeArithmeticType(value);
242     }
243
244     HistoryEntryDataDecoder& operator>>(String& value)
245     {
246         value = String();
247
248         uint32_t length;
249         *this >> length;
250
251         if (length == std::numeric_limits<uint32_t>::max()) {
252             // This is the null string.
253             value = String();
254             return *this;
255         }
256
257         uint64_t lengthInBytes;
258         *this >> lengthInBytes;
259
260         if (lengthInBytes % sizeof(UChar) || lengthInBytes / sizeof(UChar) != length) {
261             markInvalid();
262             return *this;
263         }
264
265         if (!bufferIsLargeEnoughToContain<UChar>(length)) {
266             markInvalid();
267             return *this;
268         }
269
270         UChar* buffer;
271         auto string = String::createUninitialized(length, buffer);
272         decodeFixedLengthData(reinterpret_cast<uint8_t*>(buffer), length * sizeof(UChar), alignof(UChar));
273
274         value = string;
275         return *this;
276     }
277
278     HistoryEntryDataDecoder& operator>>(Vector<uint8_t>& value)
279     {
280         value = { };
281
282         uint64_t size;
283         *this >> size;
284
285         if (!alignBufferPosition(1, size))
286             return *this;
287
288         const uint8_t* data = m_buffer;
289         m_buffer += size;
290
291         value.append(data, size);
292         return *this;
293     }
294
295     HistoryEntryDataDecoder& operator>>(Vector<char>& value)
296     {
297         value = { };
298
299         uint64_t size;
300         *this >> size;
301
302         if (!alignBufferPosition(1, size))
303             return *this;
304
305         const uint8_t* data = m_buffer;
306         m_buffer += size;
307
308         value.append(data, size);
309         return *this;
310     }
311
312     template<typename T>
313     auto operator>>(Optional<T>& value) -> typename std::enable_if<std::is_enum<T>::value, HistoryEntryDataDecoder&>::type
314     {
315         uint32_t underlyingEnumValue;
316         *this >> underlyingEnumValue;
317
318         if (!isValid() || !isValidEnum(static_cast<T>(underlyingEnumValue)))
319             value = Nullopt;
320         else
321             value = static_cast<T>(underlyingEnumValue);
322
323         return *this;
324     }
325
326     bool isValid() const { return m_buffer <= m_bufferEnd; }
327
328     bool finishDecoding() { return m_buffer == m_bufferEnd; }
329
330 private:
331     template<typename Type>
332     HistoryEntryDataDecoder& decodeArithmeticType(Type& value)
333     {
334         static_assert(std::is_arithmetic<Type>::value, "");
335         value = Type();
336
337         decodeFixedLengthData(reinterpret_cast<uint8_t*>(&value), sizeof(value), sizeof(value));
338         return *this;
339     }
340
341     void decodeFixedLengthData(uint8_t* data, size_t size, unsigned alignment)
342     {
343         if (!alignBufferPosition(alignment, size))
344             return;
345
346         memcpy(data, m_buffer, size);
347         m_buffer += size;
348     }
349
350     bool alignBufferPosition(unsigned alignment, size_t size)
351     {
352         const uint8_t* alignedPosition = alignedBuffer(alignment);
353         if (!alignedBufferIsLargeEnoughToContain(alignedPosition, size)) {
354             // We've walked off the end of this buffer.
355             markInvalid();
356             return false;
357         }
358
359         m_buffer = alignedPosition;
360         return true;
361     }
362
363     const uint8_t* alignedBuffer(unsigned alignment) const
364     {
365         ASSERT(alignment && !(alignment & (alignment - 1)));
366
367         uintptr_t alignmentMask = alignment - 1;
368         return reinterpret_cast<uint8_t*>((reinterpret_cast<uintptr_t>(m_buffer) + alignmentMask) & ~alignmentMask);
369     }
370
371     template<typename T>
372     bool bufferIsLargeEnoughToContain(size_t numElements) const
373     {
374         static_assert(std::is_arithmetic<T>::value, "Type T must have a fixed, known encoded size!");
375
376         if (numElements > std::numeric_limits<size_t>::max() / sizeof(T))
377             return false;
378
379         return bufferIsLargeEnoughToContain(alignof(T), numElements * sizeof(T));
380     }
381
382     bool bufferIsLargeEnoughToContain(unsigned alignment, size_t size) const
383     {
384         return alignedBufferIsLargeEnoughToContain(alignedBuffer(alignment), size);
385     }
386
387     inline bool alignedBufferIsLargeEnoughToContain(const uint8_t* alignedPosition, size_t size) const
388     {
389         return m_bufferEnd >= alignedPosition && static_cast<size_t>(m_bufferEnd - alignedPosition) >= size;
390     }
391
392     void markInvalid() { m_buffer = m_bufferEnd + 1; }
393
394     const uint8_t* m_buffer;
395     const uint8_t* m_bufferEnd;
396 };
397
398 enum class FormDataElementType {
399     Data = 0,
400     EncodedFile = 1,
401     EncodedBlob = 2,
402 };
403
404 static bool isValidEnum(FormDataElementType type)
405 {
406     switch (type) {
407     case FormDataElementType::Data:
408     case FormDataElementType::EncodedFile:
409     case FormDataElementType::EncodedBlob:
410         return true;
411     }
412
413     return false;
414 }
415
416 static void decodeFormDataElement(HistoryEntryDataDecoder& decoder, HTTPBody::Element& formDataElement)
417 {
418     Optional<FormDataElementType> elementType;
419     decoder >> elementType;
420     if (!elementType)
421         return;
422
423     switch (elementType.value()) {
424     case FormDataElementType::Data:
425         formDataElement.type = HTTPBody::Element::Type::Data;
426         decoder >> formDataElement.data;
427         break;
428
429     case FormDataElementType::EncodedFile:
430     case FormDataElementType::EncodedBlob:
431         // FIXME: Implement.
432         ASSERT_NOT_REACHED();
433     }
434 }
435
436 static void decodeFormData(HistoryEntryDataDecoder& decoder, HTTPBody& formData)
437 {
438     bool alwaysStream;
439     decoder >> alwaysStream;
440
441     Vector<uint8_t> boundary;
442     decoder >> boundary;
443
444     uint64_t formDataElementCount;
445     decoder >> formDataElementCount;
446
447     for (uint64_t i = 0; i < formDataElementCount; ++i) {
448         HTTPBody::Element formDataElement;
449         decodeFormDataElement(decoder, formDataElement);
450
451         formData.elements.append(std::move(formDataElement));
452     }
453 }
454
455 static void decodeBackForwardTreeNode(HistoryEntryDataDecoder& decoder, FrameState& frameState)
456 {
457     uint64_t childCount;
458     decoder >> childCount;
459
460     for (uint64_t i = 0; i < childCount; ++i) {
461         FrameState childFrameState;
462         decoder >> childFrameState.originalURLString;
463         decoder >> childFrameState.urlString;
464
465         decodeBackForwardTreeNode(decoder, childFrameState);
466         frameState.children.append(std::move(childFrameState));
467     }
468
469     decoder >> frameState.documentSequenceNumber;
470
471     uint64_t documentStateVectorSize;
472     decoder >> documentStateVectorSize;
473
474     for (uint64_t i = 0; i < documentStateVectorSize; ++i) {
475         // FIXME: Implement.
476         ASSERT_NOT_REACHED();
477     }
478
479     String formContentType;
480     decoder >> formContentType;
481
482     bool hasFormData;
483     decoder >> hasFormData;
484
485     if (hasFormData) {
486         HTTPBody httpBody;
487         httpBody.contentType = std::move(formContentType);
488
489         decodeFormData(decoder, httpBody);
490
491         frameState.httpBody = std::move(httpBody);
492     }
493
494     decoder >> frameState.itemSequenceNumber;
495
496     decoder >> frameState.referrer;
497
498     int32_t scrollPointX;
499     decoder >> scrollPointX;
500
501     int32_t scrollPointY;
502     decoder >> scrollPointY;
503
504     frameState.scrollPoint = WebCore::IntPoint(scrollPointX, scrollPointY);
505
506     decoder >> frameState.pageScaleFactor;
507
508     bool hasStateObject;
509     decoder >> hasStateObject;
510
511     if (hasStateObject) {
512         // FIXME: Implement.
513         ASSERT_NOT_REACHED();
514     }
515
516     decoder >> frameState.target;
517 }
518
519 bool LegacySessionStateDecoder::decodeSessionHistoryEntryData(CFDataRef historyEntryData, FrameState& mainFrameState) const
520 {
521     HistoryEntryDataDecoder decoder { CFDataGetBytePtr(historyEntryData), static_cast<size_t>(CFDataGetLength(historyEntryData)) };
522
523     uint32_t version;
524     decoder >> version;
525
526     if (version != sessionHistoryEntryDataVersion)
527         return false;
528
529     decodeBackForwardTreeNode(decoder, mainFrameState);
530
531     return decoder.finishDecoding();
532 }
533
534
535 } // namespace WebKit