blob: 371715a27fd0c34715ac8ea4ab704afb05809619 [file] [log] [blame]
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "SessionStateConversion.h"
#include "SessionState.h"
#include <WebCore/BlobData.h>
#include <WebCore/FormData.h>
#include <WebCore/HistoryItem.h>
#include <wtf/FileSystem.h>
namespace WebKit {
using namespace WebCore;
static HTTPBody toHTTPBody(const FormData& formData)
{
HTTPBody httpBody;
for (const auto& formDataElement : formData.elements()) {
HTTPBody::Element element;
switchOn(formDataElement.data,
[&] (const Vector<uint8_t>& bytes) {
element.type = HTTPBody::Element::Type::Data;
element.data = bytes;
}, [&] (const FormDataElement::EncodedFileData& fileData) {
element.filePath = fileData.filename;
element.fileStart = fileData.fileStart;
if (fileData.fileLength != BlobDataItem::toEndOfFile)
element.fileLength = fileData.fileLength;
element.expectedFileModificationTime = fileData.expectedFileModificationTime;
}, [&] (const FormDataElement::EncodedBlobData& blobData) {
element.blobURLString = blobData.url.string();
}
);
httpBody.elements.append(WTFMove(element));
}
return httpBody;
}
static FrameState toFrameState(const HistoryItem& historyItem)
{
FrameState frameState;
frameState.urlString = historyItem.urlString();
frameState.originalURLString = historyItem.originalURLString();
frameState.referrer = historyItem.referrer();
frameState.target = historyItem.target();
frameState.setDocumentState(historyItem.documentState());
if (RefPtr<SerializedScriptValue> stateObject = historyItem.stateObject())
frameState.stateObjectData = stateObject->wireBytes();
frameState.documentSequenceNumber = historyItem.documentSequenceNumber();
frameState.itemSequenceNumber = historyItem.itemSequenceNumber();
frameState.scrollPosition = historyItem.scrollPosition();
frameState.shouldRestoreScrollPosition = historyItem.shouldRestoreScrollPosition();
frameState.pageScaleFactor = historyItem.pageScaleFactor();
if (FormData* formData = const_cast<HistoryItem&>(historyItem).formData()) {
HTTPBody httpBody = toHTTPBody(*formData);
httpBody.contentType = historyItem.formContentType();
frameState.httpBody = WTFMove(httpBody);
}
#if PLATFORM(IOS_FAMILY)
frameState.exposedContentRect = historyItem.exposedContentRect();
frameState.unobscuredContentRect = historyItem.unobscuredContentRect();
frameState.minimumLayoutSizeInScrollViewCoordinates = historyItem.minimumLayoutSizeInScrollViewCoordinates();
frameState.contentSize = historyItem.contentSize();
frameState.scaleIsInitial = historyItem.scaleIsInitial();
frameState.obscuredInsets = historyItem.obscuredInsets();
#endif
frameState.children = historyItem.children().map([](auto& childHistoryItem) {
return toFrameState(childHistoryItem);
});
return frameState;
}
BackForwardListItemState toBackForwardListItemState(const WebCore::HistoryItem& historyItem)
{
BackForwardListItemState state;
state.identifier = historyItem.identifier();
state.pageState.title = historyItem.title();
state.pageState.mainFrameState = toFrameState(historyItem);
state.pageState.shouldOpenExternalURLsPolicy = historyItem.shouldOpenExternalURLsPolicy();
state.pageState.sessionStateObject = historyItem.stateObject();
state.pageState.wasCreatedByJSWithoutUserInteraction = historyItem.wasCreatedByJSWithoutUserInteraction();
state.hasCachedPage = historyItem.isInBackForwardCache();
return state;
}
static Ref<FormData> toFormData(const HTTPBody& httpBody)
{
auto formData = FormData::create();
for (const auto& element : httpBody.elements) {
switch (element.type) {
case HTTPBody::Element::Type::Data:
formData->appendData(element.data.data(), element.data.size());
break;
case HTTPBody::Element::Type::File:
formData->appendFileRange(element.filePath, element.fileStart, element.fileLength.value_or(BlobDataItem::toEndOfFile), element.expectedFileModificationTime);
break;
case HTTPBody::Element::Type::Blob:
formData->appendBlob(URL { element.blobURLString });
break;
}
}
return formData;
}
static void applyFrameState(HistoryItem& historyItem, const FrameState& frameState)
{
historyItem.setOriginalURLString(frameState.originalURLString);
historyItem.setReferrer(frameState.referrer);
historyItem.setTarget(frameState.target);
historyItem.setDocumentState(frameState.documentState());
if (frameState.stateObjectData) {
Vector<uint8_t> stateObjectData = frameState.stateObjectData.value();
historyItem.setStateObject(SerializedScriptValue::createFromWireBytes(WTFMove(stateObjectData)));
}
historyItem.setDocumentSequenceNumber(frameState.documentSequenceNumber);
historyItem.setItemSequenceNumber(frameState.itemSequenceNumber);
historyItem.setScrollPosition(frameState.scrollPosition);
historyItem.setShouldRestoreScrollPosition(frameState.shouldRestoreScrollPosition);
historyItem.setPageScaleFactor(frameState.pageScaleFactor);
if (frameState.httpBody) {
const auto& httpBody = frameState.httpBody.value();
historyItem.setFormContentType(httpBody.contentType);
historyItem.setFormData(toFormData(httpBody));
}
#if PLATFORM(IOS_FAMILY)
historyItem.setExposedContentRect(frameState.exposedContentRect);
historyItem.setUnobscuredContentRect(frameState.unobscuredContentRect);
historyItem.setMinimumLayoutSizeInScrollViewCoordinates(frameState.minimumLayoutSizeInScrollViewCoordinates);
historyItem.setContentSize(frameState.contentSize);
historyItem.setScaleIsInitial(frameState.scaleIsInitial);
historyItem.setObscuredInsets(frameState.obscuredInsets);
#endif
for (const auto& childFrameState : frameState.children) {
Ref<HistoryItem> childHistoryItem = HistoryItem::create(childFrameState.urlString, { }, { });
applyFrameState(childHistoryItem, childFrameState);
historyItem.addChildItem(WTFMove(childHistoryItem));
}
}
Ref<HistoryItem> toHistoryItem(const BackForwardListItemState& itemState)
{
Ref<HistoryItem> historyItem = HistoryItem::create(itemState.pageState.mainFrameState.urlString, itemState.pageState.title, { }, itemState.identifier);
historyItem->setShouldOpenExternalURLsPolicy(itemState.pageState.shouldOpenExternalURLsPolicy);
historyItem->setStateObject(itemState.pageState.sessionStateObject.get());
applyFrameState(historyItem, itemState.pageState.mainFrameState);
return historyItem;
}
} // namespace WebKit