2021-08-14 07:25:10 +00:00
|
|
|
/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
|
2009-01-28 20:55:45 +00:00
|
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
|
2009-04-27 12:25:15 +00:00
|
|
|
#include <stdint.h>
|
2013-05-31 04:20:25 +00:00
|
|
|
#include <QUrl>
|
2009-01-28 20:55:45 +00:00
|
|
|
#include "article_netmgr.hh"
|
2013-11-16 18:34:09 +00:00
|
|
|
#include "gddebug.hh"
|
2021-11-27 07:17:33 +00:00
|
|
|
#include "utils.hh"
|
2021-08-05 06:57:22 +00:00
|
|
|
#include <QNetworkAccessManager>
|
2023-04-17 21:56:55 +00:00
|
|
|
#include "globalbroadcaster.hh"
|
2013-05-30 13:24:21 +00:00
|
|
|
|
2009-01-28 20:55:45 +00:00
|
|
|
using std::string;
|
|
|
|
|
2017-03-23 15:03:17 +00:00
|
|
|
// AllowFrameReply
|
|
|
|
|
|
|
|
AllowFrameReply::AllowFrameReply( QNetworkReply * _reply ):
|
|
|
|
baseReply( _reply )
|
|
|
|
{
|
|
|
|
// Set base data
|
|
|
|
|
|
|
|
setOperation( baseReply->operation() );
|
|
|
|
setRequest( baseReply->request() );
|
|
|
|
setUrl( baseReply->url() );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
// Signals to own slots
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::metaDataChanged, this, &AllowFrameReply::applyMetaData );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::errorOccurred, this, &AllowFrameReply::applyError );
|
2017-03-24 14:05:22 +00:00
|
|
|
|
2017-03-23 15:03:17 +00:00
|
|
|
connect( baseReply, &QIODevice::readyRead, this, &QIODevice::readyRead );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
// Redirect QNetworkReply signals
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::downloadProgress, this, &QNetworkReply::downloadProgress );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::encrypted, this, &QNetworkReply::encrypted );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::finished, this, &QNetworkReply::finished );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply,
|
|
|
|
&QNetworkReply::preSharedKeyAuthenticationRequired,
|
|
|
|
this,
|
|
|
|
&QNetworkReply::preSharedKeyAuthenticationRequired );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::redirected, this, &QNetworkReply::redirected );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QNetworkReply::sslErrors, this, &QNetworkReply::sslErrors );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
|
|
|
connect( baseReply, &QNetworkReply::uploadProgress, this, &QNetworkReply::uploadProgress );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
// Redirect QIODevice signals
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QIODevice::aboutToClose, this, &QIODevice::aboutToClose );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( baseReply, &QIODevice::bytesWritten, this, &QIODevice::bytesWritten );
|
2017-03-23 15:03:17 +00:00
|
|
|
|
|
|
|
connect( baseReply, &QIODevice::readChannelFinished, this, &QIODevice::readChannelFinished );
|
|
|
|
|
|
|
|
setOpenMode( QIODevice::ReadOnly );
|
|
|
|
}
|
|
|
|
|
|
|
|
void AllowFrameReply::applyMetaData()
|
2023-07-20 08:02:22 +00:00
|
|
|
{
|
2017-03-23 15:03:17 +00:00
|
|
|
// Set raw headers except X-Frame-Options
|
|
|
|
QList< QByteArray > rawHeaders = baseReply->rawHeaderList();
|
|
|
|
for ( QList< QByteArray >::iterator it = rawHeaders.begin(); it != rawHeaders.end(); ++it ) {
|
|
|
|
auto headerName = it->toLower();
|
|
|
|
if ( headerName != "x-frame-options" && headerName != "content-security-policy" )
|
|
|
|
setRawHeader( *it, baseReply->rawHeader( *it ) );
|
|
|
|
}
|
|
|
|
|
2017-03-24 14:05:22 +00:00
|
|
|
// Set known headers
|
|
|
|
setHeader( QNetworkRequest::ContentDispositionHeader,
|
|
|
|
baseReply->header( QNetworkRequest::ContentDispositionHeader ) );
|
2009-01-28 20:55:45 +00:00
|
|
|
setHeader( QNetworkRequest::ContentTypeHeader, baseReply->header( QNetworkRequest::ContentTypeHeader ) );
|
2017-03-23 15:03:17 +00:00
|
|
|
setHeader( QNetworkRequest::ContentLengthHeader, baseReply->header( QNetworkRequest::ContentLengthHeader ) );
|
2017-03-24 14:05:22 +00:00
|
|
|
setHeader( QNetworkRequest::LocationHeader, baseReply->header( QNetworkRequest::LocationHeader ) );
|
2017-03-23 15:03:17 +00:00
|
|
|
setHeader( QNetworkRequest::LastModifiedHeader, baseReply->header( QNetworkRequest::LastModifiedHeader ) );
|
|
|
|
setHeader( QNetworkRequest::CookieHeader, baseReply->header( QNetworkRequest::CookieHeader ) );
|
2017-03-24 14:05:22 +00:00
|
|
|
setHeader( QNetworkRequest::SetCookieHeader, baseReply->header( QNetworkRequest::SetCookieHeader ) );
|
2017-03-23 15:03:17 +00:00
|
|
|
setHeader( QNetworkRequest::UserAgentHeader, baseReply->header( QNetworkRequest::UserAgentHeader ) );
|
|
|
|
setHeader( QNetworkRequest::ServerHeader, baseReply->header( QNetworkRequest::ServerHeader ) );
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2017-03-24 14:05:22 +00:00
|
|
|
// Set attributes
|
2017-03-23 15:03:17 +00:00
|
|
|
setAttribute( QNetworkRequest::HttpStatusCodeAttribute,
|
|
|
|
baseReply->attribute( QNetworkRequest::HttpStatusCodeAttribute ) );
|
|
|
|
setAttribute( QNetworkRequest::HttpReasonPhraseAttribute,
|
2017-03-24 14:05:22 +00:00
|
|
|
baseReply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ) );
|
|
|
|
setAttribute( QNetworkRequest::RedirectionTargetAttribute,
|
2017-03-23 15:03:17 +00:00
|
|
|
baseReply->attribute( QNetworkRequest::RedirectionTargetAttribute ) );
|
|
|
|
setAttribute( QNetworkRequest::ConnectionEncryptedAttribute,
|
|
|
|
baseReply->attribute( QNetworkRequest::ConnectionEncryptedAttribute ) );
|
|
|
|
setAttribute( QNetworkRequest::SourceIsFromCacheAttribute,
|
2017-03-24 14:05:22 +00:00
|
|
|
baseReply->attribute( QNetworkRequest::SourceIsFromCacheAttribute ) );
|
|
|
|
setAttribute( QNetworkRequest::HttpPipeliningWasUsedAttribute,
|
|
|
|
baseReply->attribute( QNetworkRequest::HttpPipeliningWasUsedAttribute ) );
|
2017-03-23 15:03:17 +00:00
|
|
|
setAttribute( QNetworkRequest::BackgroundRequestAttribute,
|
2017-03-24 14:05:22 +00:00
|
|
|
baseReply->attribute( QNetworkRequest::BackgroundRequestAttribute ) );
|
2022-01-08 13:16:22 +00:00
|
|
|
setAttribute( QNetworkRequest::Http2WasUsedAttribute,
|
|
|
|
baseReply->attribute( QNetworkRequest::Http2WasUsedAttribute ) );
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2017-03-24 14:05:22 +00:00
|
|
|
emit metaDataChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AllowFrameReply::setReadBufferSize( qint64 size )
|
|
|
|
{
|
2017-03-23 15:03:17 +00:00
|
|
|
QNetworkReply::setReadBufferSize( size );
|
2022-05-13 16:00:23 +00:00
|
|
|
baseReply->setReadBufferSize( size );
|
2017-03-24 14:05:22 +00:00
|
|
|
}
|
|
|
|
|
2017-03-23 15:03:17 +00:00
|
|
|
qint64 AllowFrameReply::bytesAvailable() const
|
|
|
|
{
|
|
|
|
return baseReply->bytesAvailable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AllowFrameReply::applyError( QNetworkReply::NetworkError code )
|
2023-07-20 08:02:22 +00:00
|
|
|
{
|
2017-03-23 15:03:17 +00:00
|
|
|
setError( code, baseReply->errorString() );
|
2022-01-08 13:16:22 +00:00
|
|
|
emit errorOccurred( code );
|
2023-07-20 08:02:22 +00:00
|
|
|
}
|
|
|
|
|
2017-03-24 14:05:22 +00:00
|
|
|
qint64 AllowFrameReply::readData( char * data, qint64 maxSize )
|
|
|
|
{
|
2022-05-13 16:00:23 +00:00
|
|
|
auto bytesAvailable = baseReply->bytesAvailable();
|
|
|
|
qint64 size = qMin( maxSize, bytesAvailable );
|
|
|
|
baseReply->read( data, size );
|
2017-03-24 14:05:22 +00:00
|
|
|
return size;
|
|
|
|
}
|
2023-03-26 06:46:27 +00:00
|
|
|
void AllowFrameReply::finishedSlot()
|
|
|
|
{
|
|
|
|
setFinished( true );
|
|
|
|
emit finished();
|
|
|
|
}
|
2017-03-24 14:05:22 +00:00
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
QNetworkReply * ArticleNetworkAccessManager::getArticleReply( QNetworkRequest const & req )
|
2009-01-28 20:55:45 +00:00
|
|
|
{
|
2022-05-13 16:00:23 +00:00
|
|
|
QUrl url;
|
2022-05-18 23:14:36 +00:00
|
|
|
auto op = GetOperation;
|
2023-03-26 06:46:27 +00:00
|
|
|
|
|
|
|
if ( req.url().scheme() == "qrcx" ) {
|
2023-03-05 20:20:05 +00:00
|
|
|
// We had to override the local load policy for the qrc URL scheme until QWebSecurityOrigin::addLocalScheme() was
|
|
|
|
// introduced in Qt 4.6. Hence we used a custom qrcx URL scheme and redirected it here back to qrc. Qt versions
|
|
|
|
// older than 4.6 are no longer supported, so GoldenDict itself no longer uses the qrcx scheme. However, qrcx has
|
|
|
|
// been used for many years in our built-in article styles, and so may appear in user-defined article styles.
|
|
|
|
// TODO: deprecate (print a warning or show a warning message box) and eventually remove support for the obsolete
|
|
|
|
// qrcx URL scheme. A recent commit "Add support for qrc:// URL scheme" is the first one where the qrc scheme
|
|
|
|
// works correctly. So the deprecation has to wait until older GoldenDict versions become rarely used.
|
2013-05-31 04:20:25 +00:00
|
|
|
QUrl newUrl( req.url() );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
newUrl.setScheme( "qrc" );
|
|
|
|
newUrl.setHost( "" );
|
|
|
|
|
|
|
|
QNetworkRequest newReq( req );
|
|
|
|
newReq.setUrl( newUrl );
|
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
return QNetworkAccessManager::createRequest( op, newReq, nullptr );
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2022-05-13 16:00:23 +00:00
|
|
|
url = req.url();
|
2021-12-27 13:15:13 +00:00
|
|
|
QMimeType mineType = db.mimeTypeForUrl( url );
|
|
|
|
QString contentType = mineType.name();
|
|
|
|
|
2021-09-24 13:08:54 +00:00
|
|
|
if ( req.url().scheme() == "gdlookup" ) {
|
|
|
|
QString path = url.path();
|
2022-11-19 06:12:31 +00:00
|
|
|
if ( !path.isEmpty() ) {
|
|
|
|
url.setPath( "" );
|
|
|
|
|
|
|
|
Utils::Url::addQueryItem( url, "word", path.mid( 1 ) );
|
2022-11-24 12:34:21 +00:00
|
|
|
Utils::Url::addQueryItem( url, "group", QString::number( GlobalBroadcaster::instance()->currentGroupId ) );
|
2021-09-24 13:08:54 +00:00
|
|
|
}
|
2023-07-20 08:02:22 +00:00
|
|
|
}
|
2021-09-24 13:08:54 +00:00
|
|
|
|
|
|
|
sptr< Dictionary::DataRequest > dr = getResource( url, contentType );
|
2009-03-26 19:00:08 +00:00
|
|
|
|
|
|
|
if ( dr.get() )
|
|
|
|
return new ArticleResourceReply( this, req, dr, contentType );
|
2022-01-11 14:20:38 +00:00
|
|
|
|
|
|
|
//dr.get() can be null. code continue to execute.
|
|
|
|
|
|
|
|
//can not match dictionary in the above code,means the url must be external links.
|
|
|
|
//if not external url,can be blocked from here. no need to continue execute the following code.
|
|
|
|
//such as bres://upload.wikimedia.... etc .
|
2022-05-13 16:00:23 +00:00
|
|
|
if ( !Utils::isExternalLink( url ) ) {
|
2022-04-19 16:40:41 +00:00
|
|
|
gdWarning( "Blocking element \"%s\" as built-in link ", req.url().toEncoded().data() );
|
2022-01-11 14:20:38 +00:00
|
|
|
return new BlockedNetworkReply( this );
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2009-08-31 12:18:08 +00:00
|
|
|
// Check the Referer. If the user has opted-in to block elements from external
|
|
|
|
// pages, we block them.
|
|
|
|
|
|
|
|
if ( disallowContentFromOtherSites && req.hasRawHeader( "Referer" ) ) {
|
|
|
|
QByteArray referer = req.rawHeader( "Referer" );
|
|
|
|
|
2013-05-31 04:20:25 +00:00
|
|
|
QUrl refererUrl = QUrl::fromEncoded( referer );
|
2009-08-31 12:18:08 +00:00
|
|
|
|
2022-05-13 16:00:23 +00:00
|
|
|
if ( !url.host().endsWith( refererUrl.host() )
|
2022-10-15 05:58:24 +00:00
|
|
|
&& Utils::Url::getHostBaseFromUrl( url ) != Utils::Url::getHostBaseFromUrl( refererUrl )
|
|
|
|
&& !url.scheme().startsWith( "data" ) ) {
|
2022-05-13 16:00:23 +00:00
|
|
|
gdWarning( "Blocking element \"%s\" due to not same domain", url.toEncoded().data() );
|
2009-08-31 12:18:08 +00:00
|
|
|
|
|
|
|
return new BlockedNetworkReply( this );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-13 20:21:33 +00:00
|
|
|
if ( req.url().scheme() == "file" ) {
|
|
|
|
// Check file presence and adjust path if necessary
|
|
|
|
QString fileName = req.url().toLocalFile();
|
|
|
|
if ( req.url().host().isEmpty() && articleMaker.adjustFilePath( fileName ) ) {
|
2013-05-31 04:20:25 +00:00
|
|
|
QUrl newUrl( req.url() );
|
2019-08-05 14:51:57 +00:00
|
|
|
QUrl localUrl = QUrl::fromLocalFile( fileName );
|
|
|
|
|
|
|
|
newUrl.setHost( localUrl.host() );
|
2021-11-27 07:17:33 +00:00
|
|
|
newUrl.setPath( Utils::Url::ensureLeadingSlash( localUrl.path() ) );
|
2012-12-13 20:21:33 +00:00
|
|
|
|
|
|
|
QNetworkRequest newReq( req );
|
|
|
|
newReq.setUrl( newUrl );
|
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
return QNetworkAccessManager::createRequest( op, newReq, nullptr );
|
2012-12-13 20:21:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-08 12:20:12 +00:00
|
|
|
// spoof User-Agent
|
2022-05-13 16:00:23 +00:00
|
|
|
QNetworkRequest newReq;
|
|
|
|
newReq.setUrl( url );
|
|
|
|
newReq.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy );
|
|
|
|
if ( hideGoldenDictHeader && url.scheme().startsWith( "http", Qt::CaseInsensitive ) ) {
|
2022-01-08 13:16:22 +00:00
|
|
|
newReq.setRawHeader( "User-Agent", req.rawHeader( "User-Agent" ).replace( qApp->applicationName().toUtf8(), "" ) );
|
2016-06-25 12:37:08 +00:00
|
|
|
}
|
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
QNetworkReply * reply = QNetworkAccessManager::createRequest( op, newReq, nullptr );
|
2016-06-25 12:37:08 +00:00
|
|
|
|
2022-05-13 16:00:23 +00:00
|
|
|
if ( url.scheme() == "https" ) {
|
2022-12-15 07:11:09 +00:00
|
|
|
#ifndef QT_NO_SSL
|
2016-06-25 12:37:08 +00:00
|
|
|
connect( reply, SIGNAL( sslErrors( QList< QSslError > ) ), reply, SLOT( ignoreSslErrors() ) );
|
|
|
|
#endif
|
2013-04-08 12:20:12 +00:00
|
|
|
}
|
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
return new AllowFrameReply( reply );
|
2021-08-05 06:57:22 +00:00
|
|
|
}
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
sptr< Dictionary::DataRequest > ArticleNetworkAccessManager::getResource( QUrl const & url, QString & contentType )
|
2009-01-28 20:55:45 +00:00
|
|
|
{
|
2022-10-22 05:42:17 +00:00
|
|
|
qDebug() << "getResource:" << url.toString();
|
|
|
|
qDebug() << "scheme:" << url.scheme();
|
|
|
|
qDebug() << "host:" << url.host();
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
if ( url.scheme() == "gdlookup" ) {
|
2014-05-23 17:43:44 +00:00
|
|
|
if ( !url.host().isEmpty() && url.host() != "localhost" ) {
|
|
|
|
// Strange request - ignore it
|
2022-11-29 03:54:31 +00:00
|
|
|
return std::make_shared< Dictionary::DataRequestInstant >( false );
|
2014-05-23 17:43:44 +00:00
|
|
|
}
|
|
|
|
|
2009-05-11 15:33:57 +00:00
|
|
|
contentType = "text/html";
|
|
|
|
|
2021-11-27 07:17:33 +00:00
|
|
|
if ( Utils::Url::queryItemValue( url, "blank" ) == "1" )
|
2009-05-11 15:33:57 +00:00
|
|
|
return articleMaker.makeEmptyPage();
|
|
|
|
|
2023-05-28 16:01:54 +00:00
|
|
|
QString word = Utils::Url::queryItemValue( url, "word" ).trimmed();
|
2009-04-10 12:48:40 +00:00
|
|
|
|
2021-06-10 16:13:11 +00:00
|
|
|
bool groupIsValid = false;
|
2021-11-27 07:17:33 +00:00
|
|
|
unsigned group = Utils::Url::queryItemValue( url, "group" ).toUInt( &groupIsValid );
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2021-11-27 07:17:33 +00:00
|
|
|
QString dictIDs = Utils::Url::queryItemValue( url, "dictionaries" );
|
2014-04-16 16:18:28 +00:00
|
|
|
if ( !dictIDs.isEmpty() ) {
|
|
|
|
// Individual dictionaries set from full-text search
|
|
|
|
QStringList dictIDList = dictIDs.split( "," );
|
2023-05-28 16:01:54 +00:00
|
|
|
return articleMaker.makeDefinitionFor( word, group, QMap< QString, QString >(), QSet< QString >(), dictIDList );
|
2014-04-16 16:18:28 +00:00
|
|
|
}
|
|
|
|
|
2009-09-23 18:44:38 +00:00
|
|
|
// See if we have some dictionaries muted
|
|
|
|
|
2022-01-08 13:16:22 +00:00
|
|
|
QStringList mutedDictLists = Utils::Url::queryItemValue( url, "muted" ).split( ',' );
|
|
|
|
QSet< QString > mutedDicts( mutedDictLists.begin(), mutedDictLists.end() );
|
2009-09-23 18:44:38 +00:00
|
|
|
|
2009-05-29 19:48:50 +00:00
|
|
|
// Unpack contexts
|
|
|
|
|
|
|
|
QMap< QString, QString > contexts;
|
|
|
|
|
2021-11-27 07:17:33 +00:00
|
|
|
QString contextsEncoded = Utils::Url::queryItemValue( url, "contexts" );
|
2009-05-29 19:48:50 +00:00
|
|
|
|
|
|
|
if ( contextsEncoded.size() ) {
|
2013-02-03 20:19:55 +00:00
|
|
|
QByteArray ba = QByteArray::fromBase64( contextsEncoded.toLatin1() );
|
2009-05-29 19:48:50 +00:00
|
|
|
|
|
|
|
QBuffer buf( &ba );
|
|
|
|
|
|
|
|
buf.open( QBuffer::ReadOnly );
|
|
|
|
|
|
|
|
QDataStream stream( &buf );
|
|
|
|
|
|
|
|
stream >> contexts;
|
|
|
|
}
|
|
|
|
|
2018-06-13 16:00:42 +00:00
|
|
|
// See for ignore diacritics
|
|
|
|
|
2021-11-27 07:17:33 +00:00
|
|
|
bool ignoreDiacritics = Utils::Url::queryItemValue( url, "ignore_diacritics" ) == "1";
|
2018-06-13 16:00:42 +00:00
|
|
|
|
2023-05-28 16:01:54 +00:00
|
|
|
if ( groupIsValid && !word.isEmpty() ) // Require group and phrase to be passed
|
|
|
|
return articleMaker.makeDefinitionFor( word, group, contexts, mutedDicts, QStringList(), ignoreDiacritics );
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2013-06-22 16:36:25 +00:00
|
|
|
if ( ( url.scheme() == "bres" || url.scheme() == "gdau" || url.scheme() == "gdvideo" || url.scheme() == "gico" )
|
2009-01-28 20:55:45 +00:00
|
|
|
&& url.path().size() ) {
|
2022-01-15 07:29:20 +00:00
|
|
|
//GD_DPRINTF( "Get %s\n", req.url().host().toLocal8Bit().data() );
|
|
|
|
//GD_DPRINTF( "Get %s\n", req.url().path().toLocal8Bit().data() );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
string id = url.host().toStdString();
|
|
|
|
|
|
|
|
bool search = ( id == "search" );
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
if ( !search ) {
|
|
|
|
for ( unsigned x = 0; x < dictionaries.size(); ++x )
|
|
|
|
if ( dictionaries[ x ]->getId() == id ) {
|
2012-01-28 03:07:23 +00:00
|
|
|
if ( url.scheme() == "gico" ) {
|
|
|
|
QByteArray bytes;
|
|
|
|
QBuffer buffer( &bytes );
|
|
|
|
buffer.open( QIODevice::WriteOnly );
|
2022-10-26 13:00:04 +00:00
|
|
|
dictionaries[ x ]->getIcon().pixmap( 64 ).save( &buffer, "PNG" );
|
2012-01-28 03:07:23 +00:00
|
|
|
buffer.close();
|
2022-11-29 03:54:31 +00:00
|
|
|
sptr< Dictionary::DataRequestInstant > ico = std::make_shared< Dictionary::DataRequestInstant >( true );
|
2012-01-28 03:07:23 +00:00
|
|
|
ico->getData().resize( bytes.size() );
|
|
|
|
memcpy( &( ico->getData().front() ), bytes.data(), bytes.size() );
|
|
|
|
return ico;
|
|
|
|
}
|
2013-09-19 19:43:16 +00:00
|
|
|
try {
|
2021-11-27 07:17:33 +00:00
|
|
|
return dictionaries[ x ]->getResource( Utils::Url::path( url ).mid( 1 ).toUtf8().data() );
|
2013-09-19 19:43:16 +00:00
|
|
|
}
|
|
|
|
catch ( std::exception & e ) {
|
2013-11-16 18:34:09 +00:00
|
|
|
gdWarning( "getResource request error (%s) in \"%s\"\n", e.what(), dictionaries[ x ]->getName().c_str() );
|
2013-09-19 19:43:16 +00:00
|
|
|
return sptr< Dictionary::DataRequest >();
|
|
|
|
}
|
2012-01-28 03:07:23 +00:00
|
|
|
}
|
2009-03-26 19:00:08 +00:00
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 11:59:29 +00:00
|
|
|
if ( url.scheme() == "gdpicture" ) {
|
|
|
|
contentType = "text/html";
|
2013-05-31 04:20:25 +00:00
|
|
|
QUrl imgUrl( url );
|
2012-12-07 11:59:29 +00:00
|
|
|
imgUrl.setScheme( "bres" );
|
|
|
|
return articleMaker.makePicturePage( imgUrl.toEncoded().data() );
|
|
|
|
}
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
return sptr< Dictionary::DataRequest >();
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ArticleResourceReply::ArticleResourceReply( QObject * parent,
|
2009-03-26 19:00:08 +00:00
|
|
|
QNetworkRequest const & netReq,
|
|
|
|
sptr< Dictionary::DataRequest > const & req_,
|
2009-01-28 20:55:45 +00:00
|
|
|
QString const & contentType ):
|
2009-03-26 19:00:08 +00:00
|
|
|
QNetworkReply( parent ),
|
|
|
|
req( req_ ),
|
|
|
|
alreadyRead( 0 )
|
2009-01-28 20:55:45 +00:00
|
|
|
{
|
2009-03-26 19:00:08 +00:00
|
|
|
setRequest( netReq );
|
2009-01-28 20:55:45 +00:00
|
|
|
setOpenMode( ReadOnly );
|
2022-01-10 12:17:22 +00:00
|
|
|
setUrl( netReq.url() );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
|
|
|
if ( contentType.size() )
|
|
|
|
setHeader( QNetworkRequest::ContentTypeHeader, contentType );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( req.get(), &Dictionary::Request::updated, this, &ArticleResourceReply::reqUpdated );
|
|
|
|
|
|
|
|
connect( req.get(), &Dictionary::Request::finished, this, &ArticleResourceReply::reqFinished );
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
if ( req->isFinished() || req->dataSize() > 0 ) {
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( this,
|
2023-03-26 06:46:27 +00:00
|
|
|
&ArticleResourceReply::readyReadSignal,
|
|
|
|
this,
|
|
|
|
&ArticleResourceReply::readyReadSlot,
|
|
|
|
Qt::QueuedConnection );
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( this,
|
2023-03-26 06:46:27 +00:00
|
|
|
&ArticleResourceReply::finishedSignal,
|
|
|
|
this,
|
|
|
|
&ArticleResourceReply::finishedSlot,
|
|
|
|
Qt::QueuedConnection );
|
2009-03-26 19:00:08 +00:00
|
|
|
|
|
|
|
emit readyReadSignal();
|
|
|
|
|
|
|
|
if ( req->isFinished() ) {
|
|
|
|
emit finishedSignal();
|
2014-05-10 21:02:31 +00:00
|
|
|
GD_DPRINTF( "In-place finish.\n" );
|
2009-03-26 19:00:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-03-28 15:59:39 +00:00
|
|
|
ArticleResourceReply::~ArticleResourceReply()
|
|
|
|
{
|
|
|
|
req->cancel();
|
|
|
|
}
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
void ArticleResourceReply::reqUpdated()
|
|
|
|
{
|
|
|
|
emit readyRead();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ArticleResourceReply::reqFinished()
|
|
|
|
{
|
|
|
|
emit readyRead();
|
|
|
|
finishedSlot();
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qint64 ArticleResourceReply::bytesAvailable() const
|
|
|
|
{
|
2014-05-12 13:43:02 +00:00
|
|
|
qint64 avail = req->dataSize();
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
if ( avail < 0 )
|
|
|
|
return 0;
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2014-05-12 13:43:02 +00:00
|
|
|
return avail - alreadyRead + QNetworkReply::bytesAvailable();
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 03:19:11 +00:00
|
|
|
bool ArticleResourceReply::atEnd() const
|
|
|
|
{
|
|
|
|
// QWebEngineUrlRequestJob finishes and is destroyed as soon as QIODevice::atEnd() returns true.
|
|
|
|
// QNetworkReply::atEnd() returns true while bytesAvailable() returns 0.
|
|
|
|
// Return false if the data request is not finished to work around always-blank web page.
|
|
|
|
return req->isFinished() && QNetworkReply::atEnd();
|
|
|
|
}
|
|
|
|
|
2009-01-28 20:55:45 +00:00
|
|
|
qint64 ArticleResourceReply::readData( char * out, qint64 maxSize )
|
|
|
|
{
|
2013-08-04 19:19:57 +00:00
|
|
|
// From the doc: "This function might be called with a maxSize of 0,
|
|
|
|
// which can be used to perform post-reading operations".
|
|
|
|
if ( maxSize == 0 )
|
|
|
|
return 0;
|
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
bool finished = req->isFinished();
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2014-05-12 13:43:02 +00:00
|
|
|
qint64 avail = req->dataSize();
|
2009-03-26 19:00:08 +00:00
|
|
|
|
|
|
|
if ( avail < 0 )
|
|
|
|
return finished ? -1 : 0;
|
|
|
|
|
2014-05-12 13:43:02 +00:00
|
|
|
qint64 left = avail - alreadyRead;
|
2023-07-20 08:02:22 +00:00
|
|
|
|
2023-03-29 03:19:11 +00:00
|
|
|
if ( left == 0 && !finished ) {
|
|
|
|
// Work around endlessly repeated useless calls to readData(). The sleep duration is a tradeoff.
|
|
|
|
// On the one hand, lowering the duration reduces CPU usage. On the other hand, overly long
|
|
|
|
// sleep duration reduces page content update frequency in the web view.
|
|
|
|
// Waiting on a condition variable is more complex and actually works worse than
|
|
|
|
// simple fixed-duration sleeping, because the web view is not updated until
|
|
|
|
// the data request is finished if readData() returns only when new data arrives.
|
|
|
|
QThread::msleep( 30 );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-12 13:43:02 +00:00
|
|
|
qint64 toRead = maxSize < left ? maxSize : left;
|
2023-07-30 00:47:38 +00:00
|
|
|
GD_DPRINTF( "====reading %d of (%lld) bytes . Finished: %d", (int)toRead, avail, finished );
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2013-09-19 19:43:16 +00:00
|
|
|
try {
|
|
|
|
req->getDataSlice( alreadyRead, toRead, out );
|
|
|
|
}
|
|
|
|
catch ( std::exception & e ) {
|
2022-06-01 15:40:00 +00:00
|
|
|
qWarning( "getDataSlice error: %s", e.what() );
|
2013-09-19 19:43:16 +00:00
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
alreadyRead += toRead;
|
2009-01-28 20:55:45 +00:00
|
|
|
|
2009-03-26 19:00:08 +00:00
|
|
|
if ( !toRead && finished )
|
2009-01-28 20:55:45 +00:00
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return toRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ArticleResourceReply::readyReadSlot()
|
|
|
|
{
|
2021-12-27 13:15:13 +00:00
|
|
|
emit readyRead();
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ArticleResourceReply::finishedSlot()
|
|
|
|
{
|
2022-01-08 04:22:41 +00:00
|
|
|
if ( req->dataSize() < 0 ) {
|
2022-01-08 13:16:22 +00:00
|
|
|
emit errorOccurred( ContentNotFoundError );
|
2022-01-08 04:22:41 +00:00
|
|
|
setError( ContentNotFoundError, "content not found" );
|
|
|
|
}
|
2022-01-09 06:30:06 +00:00
|
|
|
//prevent sent multi times.
|
|
|
|
if ( !finishSignalSent.loadAcquire() ) {
|
|
|
|
finishSignalSent.ref();
|
2023-03-26 06:46:27 +00:00
|
|
|
setFinished( true );
|
2022-01-09 06:30:06 +00:00
|
|
|
emit finished();
|
|
|
|
}
|
2009-01-28 20:55:45 +00:00
|
|
|
}
|
|
|
|
|
2009-08-31 12:18:08 +00:00
|
|
|
BlockedNetworkReply::BlockedNetworkReply( QObject * parent ):
|
|
|
|
QNetworkReply( parent )
|
|
|
|
{
|
|
|
|
setError( QNetworkReply::ContentOperationNotPermittedError, "Content Blocked" );
|
|
|
|
|
2022-12-26 02:08:17 +00:00
|
|
|
connect( this, &BlockedNetworkReply::finishedSignal, this, &BlockedNetworkReply::finishedSlot, Qt::QueuedConnection );
|
2009-08-31 12:18:08 +00:00
|
|
|
|
|
|
|
emit finishedSignal(); // This way we call readyRead()/finished() sometime later
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BlockedNetworkReply::finishedSlot()
|
|
|
|
{
|
|
|
|
emit readyRead();
|
2023-03-26 06:46:27 +00:00
|
|
|
setFinished( true );
|
2009-08-31 12:18:08 +00:00
|
|
|
emit finished();
|
|
|
|
}
|
2021-08-05 06:57:22 +00:00
|
|
|
|
2022-12-22 01:08:41 +00:00
|
|
|
LocalSchemeHandler::LocalSchemeHandler( ArticleNetworkAccessManager & articleNetMgr, QObject * parent ):
|
|
|
|
QWebEngineUrlSchemeHandler( parent ),
|
|
|
|
mManager( articleNetMgr )
|
|
|
|
{
|
2021-08-14 07:25:10 +00:00
|
|
|
}
|
2021-10-03 11:28:26 +00:00
|
|
|
|
2021-10-02 12:48:49 +00:00
|
|
|
void LocalSchemeHandler::requestStarted( QWebEngineUrlRequestJob * requestJob )
|
2021-08-14 07:25:10 +00:00
|
|
|
{
|
2022-05-13 16:00:23 +00:00
|
|
|
QUrl url = requestJob->requestUrl();
|
|
|
|
QNetworkRequest request;
|
|
|
|
request.setUrl( url );
|
2021-09-24 12:29:13 +00:00
|
|
|
|
2022-05-27 15:10:50 +00:00
|
|
|
//all the url reached here must be either gdlookup or bword scheme.
|
2022-06-07 00:05:49 +00:00
|
|
|
auto [ valid, word ] = Utils::Url::getQueryWord( url );
|
2022-05-27 15:10:50 +00:00
|
|
|
// or the condition can be (!queryWord.first || word.isEmpty())
|
|
|
|
// ( queryWord.first && word.isEmpty() ) is only part of the above condition.
|
2022-06-07 00:05:49 +00:00
|
|
|
if ( valid && word.isEmpty() ) {
|
2022-05-27 15:10:50 +00:00
|
|
|
// invalid gdlookup url.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-18 23:14:36 +00:00
|
|
|
QNetworkReply * reply = this->mManager.getArticleReply( request );
|
2023-03-26 06:46:27 +00:00
|
|
|
requestJob->reply( "text/html", reply );
|
2022-05-13 16:00:23 +00:00
|
|
|
connect( requestJob, &QObject::destroyed, reply, &QObject::deleteLater );
|
2021-08-14 07:25:10 +00:00
|
|
|
}
|