159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
# Copyright 2015-2021 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
|
#
|
|
# This file is part of qutebrowser.
|
|
#
|
|
# qutebrowser is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# qutebrowser is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
"""QWebHistory serializer for QtWebEngine."""
|
|
|
|
from qutebrowser.qt.core import QByteArray, QDataStream, QIODevice, QUrl
|
|
|
|
from qutebrowser.utils import qtutils
|
|
|
|
|
|
# kHistoryStreamVersion = 3 was originally set when history serializing was
|
|
# implemented in QtWebEngine:
|
|
# https://codereview.qt-project.org/c/qt/qtwebengine/+/81529
|
|
#
|
|
# Qt 5.14 added version 4 which also serializes favicons:
|
|
# https://codereview.qt-project.org/c/qt/qtwebengine/+/279407
|
|
# However, we don't care about those, so let's keep it at 3.
|
|
HISTORY_STREAM_VERSION = 3
|
|
|
|
|
|
def _serialize_item(item, stream):
|
|
"""Serialize a single TabHistoryItem into a QDataStream.
|
|
|
|
Args:
|
|
item: The TabHistoryItem to write.
|
|
stream: The QDataStream to write to.
|
|
"""
|
|
# Thanks to Otter Browser:
|
|
# https://github.com/OtterBrowser/otter-browser/blob/v1.0.01/src/modules/backends/web/qtwebengine/QtWebEnginePage.cpp#L260
|
|
#
|
|
# Relevant QtWebEngine source:
|
|
# src/core/web_contents_adapter.cpp serializeNavigationHistory
|
|
#
|
|
# Sample data:
|
|
# [TabHistoryItem(active=True,
|
|
# original_url=QUrl('file:///home/florian/proj/qutebrowser/git/tests/end2end/data/numbers/1.txt'),
|
|
# title='1.txt',
|
|
# url=QUrl('file:///home/florian/proj/qutebrowser/git/tests/end2end/data/numbers/1.txt'),
|
|
# user_data={'zoom': 1.0, 'scroll-pos': QPoint()})]
|
|
|
|
## toQt(entry->GetVirtualURL());
|
|
# \x00\x00\x00Jfile:///home/florian/proj/qutebrowser/git/tests/end2end/data/numbers/1.txt
|
|
qtutils.serialize_stream(stream, item.url)
|
|
|
|
## toQt(entry->GetTitle());
|
|
# \x00\x00\x00\n\x001\x00.\x00t\x00x\x00t
|
|
stream.writeQString(item.title)
|
|
|
|
## QByteArray(encodedPageState.data(), encodedPageState.size());
|
|
# \xff\xff\xff\xff
|
|
qtutils.serialize_stream(stream, QByteArray())
|
|
|
|
## static_cast<qint32>(entry->GetTransitionType());
|
|
# chromium/ui/base/page_transition_types.h
|
|
# \x00\x00\x00\x00
|
|
stream.writeInt32(0) # PAGE_TRANSITION_LINK
|
|
|
|
## entry->GetHasPostData();
|
|
# \x00
|
|
stream.writeBool(False)
|
|
|
|
## toQt(entry->GetReferrer().url);
|
|
# \xff\xff\xff\xff
|
|
qtutils.serialize_stream(stream, QUrl())
|
|
|
|
## static_cast<qint32>(entry->GetReferrer().policy);
|
|
# chromium/third_party/WebKit/public/platform/WebReferrerPolicy.h
|
|
# \x00\x00\x00\x00
|
|
stream.writeInt32(0) # WebReferrerPolicyAlways
|
|
|
|
## toQt(entry->GetOriginalRequestURL());
|
|
# \x00\x00\x00Jfile:///home/florian/proj/qutebrowser/git/tests/end2end/data/numbers/1.txt
|
|
qtutils.serialize_stream(stream, item.original_url)
|
|
|
|
## entry->GetIsOverridingUserAgent();
|
|
# \x00
|
|
stream.writeBool(False)
|
|
|
|
## static_cast<qint64>(entry->GetTimestamp().ToInternalValue());
|
|
# \x00\x00\x00\x00^\x97$\xe7
|
|
if item.last_visited is None:
|
|
unix_msecs = 0
|
|
else:
|
|
unix_msecs = item.last_visited.toMSecsSinceEpoch()
|
|
# 11644516800000 is the number of milliseconds from
|
|
# 1601-01-01T00:00 (Windows NT Epoch) to 1970-01-01T00:00 (UNIX Epoch)
|
|
nt_usecs = (unix_msecs + 11644516800000) * 1000
|
|
stream.writeInt64(nt_usecs)
|
|
## entry->GetHttpStatusCode();
|
|
# \x00\x00\x00\xc8
|
|
stream.writeInt(200)
|
|
|
|
|
|
def serialize(items):
|
|
"""Serialize a list of TabHistoryItems to a data stream.
|
|
|
|
Args:
|
|
items: An iterable of TabHistoryItems.
|
|
|
|
Return:
|
|
A (stream, data, user_data) tuple.
|
|
stream: The reset QDataStream.
|
|
data: The QByteArray with the raw data.
|
|
cur_user_data: The user data for the current item or None.
|
|
|
|
Warning:
|
|
If 'data' goes out of scope, reading from 'stream' will result in a
|
|
segfault!
|
|
"""
|
|
data = QByteArray()
|
|
stream = QDataStream(data, QIODevice.OpenModeFlag.ReadWrite)
|
|
cur_user_data = None
|
|
|
|
current_idx = None
|
|
|
|
for i, item in enumerate(items):
|
|
if item.active:
|
|
if current_idx is not None:
|
|
raise ValueError("Multiple active items ({} and {}) "
|
|
"found!".format(current_idx, i))
|
|
current_idx = i
|
|
cur_user_data = item.user_data
|
|
|
|
if items:
|
|
if current_idx is None:
|
|
raise ValueError("No active item found!")
|
|
else:
|
|
current_idx = -1
|
|
|
|
### src/core/web_contents_adapter.cpp serializeNavigationHistory
|
|
# sample data:
|
|
# kHistoryStreamVersion
|
|
stream.writeInt(HISTORY_STREAM_VERSION) # \x00\x00\x00\x03
|
|
# count
|
|
stream.writeInt(len(items)) # \x00\x00\x00\x01
|
|
# currentIndex
|
|
stream.writeInt(current_idx) # \x00\x00\x00\x00
|
|
|
|
for item in items:
|
|
_serialize_item(item, stream)
|
|
|
|
stream.device().reset()
|
|
qtutils.check_qdatastream(stream)
|
|
return stream, data, cur_user_data
|