Qt 5.6 альфа QtWebEngine. Как работать с QWebEngineUrlRequestJob?

Я унаследовал от QWebEngineUrlSchemeHandler. Переопределенный метод requestStarted(QWebEngineUrlRequestJob *request)

После попытки вызвать QWebEngineUrlRequestJob::reply

Например

void CustomUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request)
{
    qDebug() << "CustomUrlSchemeHandler::requestStarted -->>> " << request->requestUrl();

    QMimeDatabase HelpViewer;
    QMimeType mt = HelpViewer.mimeTypeForUrl(request->requestUrl());
    const QString mimeType = mt.name();
    QByteArray arr = QString::fromStdString("<html><body>Hello world</body></html>").toUtf8();
    QBuffer *buffer = new QBuffer(&arr, this);
    buffer->open(QIODevice::ReadOnly);
    request->reply(mimeType.toLatin1(), buffer);

    return;
}

Но программа вылетает. смотрите лог:

    [1126/113403:FATAL:weak_ptr.cc(26)] Check failed: sequence_checker_.CalledOnValidSequencedThread(). WeakPtrs must be checked on the same sequenced thread.
Backtrace:
    base::debug::StackTrace::StackTrace [0x11A78691+33] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\debug\stack_trace_win.cc:205)
    logging::LogMessage::~LogMessage [0x119CB2AF+63] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\logging.cc:544)
    base::internal::WeakReference::Flag::IsValid [0x119FB75A+234] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\memory\weak_ptr.cc:28)
    base::internal::WeakReference::is_valid [0x119FB7B2+50] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\memory\weak_ptr.cc:43)
    base::WeakPtr<base::ObserverListBase<content::ServiceWorkerContextObserver> >::get [0x109EF57F+31] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\memory\weak_ptr.h:204)
    base::internal::InvokeHelper<1,void,base::internal::RunnableAdapter<void (__thiscall content::DownloadResourceHandler::*)(void)>,base::internal::TypeList<base::WeakPtr<content::DownloadResourceHandler> const &> >::MakeItSo [0x107B8ADB+11] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\bind_internal.h:300)
    base::internal::Invoker<base::IndexSequence<0>,base::internal::BindState<base::internal::RunnableAdapter<void (__thiscall content::DownloadResourceHandler::*)(void)>,void __cdecl(content::DownloadResourceHandler *),base::internal::TypeList<base::WeakPtr<c [0x107BAD0A+58] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\bind_internal.h:346)
    base::Callback<net::URLRequestContext * __cdecl(void)>::Run [0x1096CACF+47] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\callback.h:396)
    base::debug::TaskAnnotator::RunTask [0x11A9580D+541] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\debug\task_annotator.cc:64)
    base::MessageLoop::RunTask [0x119DAAF8+456] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_loop.cc:475)
    base::MessageLoop::DeferOrRunPendingTask [0x119D9204+52] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_loop.cc:485)
    base::MessageLoop::DoWork [0x119D974D+221] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_loop.cc:594)
    base::MessagePumpForIO::DoRunLoop [0x11A980A2+50] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_pump_win.cc:524)
    base::MessagePumpWin::RunWithDispatcher [0x11A99B42+130] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_pump_win.cc:51)
    base::MessagePumpWin::Run [0x11A99AAC+28] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_pump_win.cc:58)
    base::MessageLoop::RunHandler [0x119DA907+247] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_loop.cc:438)
    base::RunLoop::Run [0x11A0A2E6+70] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\run_loop.cc:56)
    base::MessageLoop::Run [0x119DA7BD+237] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\message_loop\message_loop.cc:288)
    base::Thread::Run [0x11A20AF6+22] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\threading\thread.cc:199)
    content::BrowserThreadImpl::IOThreadRun [0x10603B74+52] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\content\browser\browser_thread_impl.cc:212)
    content::BrowserThreadImpl::Run [0x1060498B+235] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\content\browser\browser_thread_impl.cc:246)
    base::Thread::ThreadMain [0x11A215F9+745] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\threading\thread.cc:248)
    base::`anonymous namespace'::ThreadFunc [0x11A283B6+262] (e:\lib\qt\qt_git\qt5\qtwebengine\src\3rdparty\chromium\base\threading\platform_thread_win.cc:84)
    BaseThreadInitThunk [0x75D57C04+36]
    RtlInitializeExceptionChain [0x77E4AD1F+143]
    RtlInitializeExceptionChain [0x77E4ACEA+90]
    (No symbol) [0x00000000]

person Yury Bely    schedule 26.11.2015    source источник
comment
Насколько я знаю, бета Qt 5.6 до сих пор не выпущена... Вы имели в виду альфу? Однако, поскольку вы используете БЕТА-версию, вас не должно удивлять сбой программы. Создайте отчет об ошибке на странице bugreports.qt.io.   -  person Felix    schedule 26.11.2015
comment
Я собираю Qt из фиксации f128a9a7e1009d9ee11665dce08d5bfafa91ef66; это последняя фиксация для 5.6 на данный момент   -  person Yury Bely    schedule 27.11.2015
comment
См. отчет об ошибке bugreports.qt.io/browse/QTBUG-49670.   -  person Yury Bely    schedule 27.11.2015


Ответы (2)


Причина сбоя не очевидна, поскольку документация Qt не ясна на Подробно о том, как QWebEngineUrlSchemeHandler следует реализовать.

Ваша программа дает сбой, потому что QWebEngineUrlRequestJob::reply() использует параметр buffer позже, вне области действия вызывающей программы, возможно, из другого потока. Локальная переменная QByteArray arr, которую вы объявили в стеке (и использовали в качестве резервного хранилища для буфера), к тому времени выйдет за пределы области действия, и QWebEngine будет обращаться к недопустимому указателю.

Другое дело, что reply() не становится владельцем переданного объекта buffer и никогда его не удаляет. Это приводит к утечке памяти. Вы не можете просто удалить его сразу после вызова reply() по той же причине, что и выше. Чтобы убедиться, что объект buffer удаляется, когда он больше не нужен, соедините сигнал destroyed() request со слотом deleteLater() buffer.

Вот полный рабочий пример без утечек:

void CustomUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request)
{
    QBuffer *buffer = new QBuffer;
    connect(request, SIGNAL(destroyed()), buffer, SLOT(deleteLater()));

    buffer->open(QIODevice::WriteOnly);
    buffer->write("<html><body>Hello world!</body></html>");
    buffer->close();

    request->reply("text/html", buffer);
}

Примечание. Вам вообще не нужно использовать QByteArray. Конструктор по умолчанию для QBuffer выделяет собственное хранилище.

person Martin Kutny    schedule 11.06.2016

Одной из причин сбоя является то, что arr выходит за пределы области видимости.
Вы должны изменить

QByteArray arr = QString::fromStdString("<html><body>Hello world</body></html>").toUtf8();
QBuffer *buffer = new QBuffer(&arr, this);

to

QByteArray *pArr = new QByteArray(QString::fromStdString("<html><body>Hello world</body></html>").toUtf8());
QBuffer *buffer = new QBuffer(pArr, this);
person Thomas Aho    schedule 16.05.2016