shared_ptr<ZLExecutionData> OPDSLink::createNetworkData(const std::string &url, NetworkOperationData &result) const { if (url.empty()) { return 0; } std::string modifiedUrl(url); rewriteUrl(modifiedUrl); return ZLNetworkManager::Instance().createXMLParserRequest( modifiedUrl, new OPDSXMLParser(new NetworkOPDSFeedReader(*this, url, result)) ); }
bool QgsWfsRequest::sendPOST( const QUrl &url, const QString &contentTypeHeader, const QByteArray &data ) { abort(); // cancel previous mIsAborted = false; mTimedout = false; mGotNonEmptyResponse = false; mErrorMessage.clear(); mErrorCode = QgsWfsRequest::NoError; mForceRefresh = true; mResponse.clear(); if ( url.toEncoded().contains( "fake_qgis_http_endpoint" ) ) { // Hack for testing purposes QUrl modifiedUrl( url ); modifiedUrl.addQueryItem( QStringLiteral( "POSTDATA" ), QString::fromUtf8( data ) ); return sendGET( modifiedUrl, true, true, false ); } QNetworkRequest request( url ); QgsSetRequestInitiatorClass( request, QStringLiteral( "QgsWfsRequest" ) ); if ( !mUri.auth().setAuthorization( request ) ) { mErrorCode = QgsWfsRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); return false; } request.setHeader( QNetworkRequest::ContentTypeHeader, contentTypeHeader ); mReply = QgsNetworkAccessManager::instance()->post( request, data ); mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT ); if ( !mUri.auth().setAuthorizationReply( mReply ) ) { mErrorCode = QgsWfsRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); return false; } connect( mReply, &QNetworkReply::finished, this, &QgsWfsRequest::replyFinished ); connect( mReply, &QNetworkReply::downloadProgress, this, &QgsWfsRequest::replyProgress ); QEventLoop loop; connect( this, &QgsWfsRequest::downloadFinished, &loop, &QEventLoop::quit ); loop.exec( QEventLoop::ExcludeUserInputEvents ); return mErrorMessage.isEmpty(); }
bool QgsWFSRequest::sendPOST( const QUrl& url, const QString& contentTypeHeader, const QByteArray& data ) { abort(); // cancel previous mIsAborted = false; mTimedout = false; mGotNonEmptyResponse = false; mErrorMessage.clear(); mErrorCode = QgsWFSRequest::NoError; mForceRefresh = true; mResponse.clear(); if ( url.toEncoded().contains( "fake_qgis_http_endpoint" ) ) { // Hack for testing purposes QUrl modifiedUrl( url ); modifiedUrl.addQueryItem( "POSTDATA", QString::fromUtf8( data ) ); return sendGET( modifiedUrl, true, true, false ); } QNetworkRequest request( url ); if ( !mUri.auth().setAuthorization( request ) ) { mErrorCode = QgsWFSRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); return false; } request.setHeader( QNetworkRequest::ContentTypeHeader, contentTypeHeader ); mReply = QgsNetworkAccessManager::instance()->post( request, data ); connect( mReply, SIGNAL( finished() ), this, SLOT( replyFinished() ) ); connect( mReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( replyProgress( qint64, qint64 ) ) ); QEventLoop loop; connect( this, SIGNAL( downloadFinished() ), &loop, SLOT( quit() ) ); loop.exec( QEventLoop::ExcludeUserInputEvents ); return mErrorMessage.isEmpty(); }
bool QgsWFSRequest::sendGET( const QUrl& url, bool synchronous, bool forceRefresh, bool cache ) { abort(); // cancel previous mIsAborted = false; mTimedout = false; mGotNonEmptyResponse = false; mErrorMessage.clear(); mErrorCode = QgsWFSRequest::NoError; mForceRefresh = forceRefresh; mResponse.clear(); QUrl modifiedUrl( url ); if ( modifiedUrl.toString().contains( "fake_qgis_http_endpoint" ) ) { // Just for testing with local files instead of http:// ressources QString modifiedUrlString = modifiedUrl.toString(); // Qt5 does URL encoding from some reason (of the FILTER parameter for example) modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() ); QgsDebugMsg( QString( "Get %1" ).arg( modifiedUrlString ) ); modifiedUrlString = modifiedUrlString.mid( QString( "http://" ).size() ); QString args = modifiedUrlString.mid( modifiedUrlString.indexOf( '?' ) ); if ( modifiedUrlString.size() > 256 ) { args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex(); } else { args.replace( "?", "_" ); args.replace( "&", "_" ); args.replace( "<", "_" ); args.replace( ">", "_" ); args.replace( "'", "_" ); args.replace( "\"", "_" ); args.replace( " ", "_" ); args.replace( ":", "_" ); args.replace( "/", "_" ); args.replace( "\n", "_" ); } #ifdef Q_OS_WIN // Passing "urls" like "http://c:/path" to QUrl 'eats' the : after c, // so we must restore it if ( modifiedUrlString[1] == '/' ) { modifiedUrlString = modifiedUrlString[0] + ":/" + modifiedUrlString.mid( 2 ); } #endif modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf( '?' ) ) + args; QgsDebugMsg( QString( "Get %1 (after laundering)" ).arg( modifiedUrlString ) ); modifiedUrl = QUrl::fromLocalFile( modifiedUrlString ); } QNetworkRequest request( modifiedUrl ); if ( !mUri.auth().setAuthorization( request ) ) { mErrorCode = QgsWFSRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); return false; } if ( cache ) { request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, forceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); } mReply = QgsNetworkAccessManager::instance()->get( request ); connect( mReply, SIGNAL( finished() ), this, SLOT( replyFinished() ) ); connect( mReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( replyProgress( qint64, qint64 ) ) ); if ( !synchronous ) return true; QEventLoop loop; connect( this, SIGNAL( downloadFinished() ), &loop, SLOT( quit() ) ); loop.exec( QEventLoop::ExcludeUserInputEvents ); return mErrorMessage.isEmpty(); }
bool QgsWfsRequest::sendGET( const QUrl &url, bool synchronous, bool forceRefresh, bool cache ) { abort(); // cancel previous mIsAborted = false; mTimedout = false; mGotNonEmptyResponse = false; mErrorMessage.clear(); mErrorCode = QgsWfsRequest::NoError; mForceRefresh = forceRefresh; mResponse.clear(); QUrl modifiedUrl( url ); // Specific code for testing if ( modifiedUrl.toString().contains( QLatin1String( "fake_qgis_http_endpoint" ) ) ) { // Just for testing with local files instead of http:// resources QString modifiedUrlString = modifiedUrl.toString(); // Qt5 does URL encoding from some reason (of the FILTER parameter for example) modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() ); QgsDebugMsgLevel( QStringLiteral( "Get %1" ).arg( modifiedUrlString ), 4 ); modifiedUrlString = modifiedUrlString.mid( QStringLiteral( "http://" ).size() ); QString args = modifiedUrlString.mid( modifiedUrlString.indexOf( '?' ) ); if ( modifiedUrlString.size() > 256 ) { args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex(); } else { args.replace( QLatin1String( "?" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "&" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "<" ), QLatin1String( "_" ) ); args.replace( QLatin1String( ">" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "'" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "\"" ), QLatin1String( "_" ) ); args.replace( QLatin1String( " " ), QLatin1String( "_" ) ); args.replace( QLatin1String( ":" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "/" ), QLatin1String( "_" ) ); args.replace( QLatin1String( "\n" ), QLatin1String( "_" ) ); } #ifdef Q_OS_WIN // Passing "urls" like "http://c:/path" to QUrl 'eats' the : after c, // so we must restore it if ( modifiedUrlString[1] == '/' ) { modifiedUrlString = modifiedUrlString[0] + ":/" + modifiedUrlString.mid( 2 ); } #endif modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf( '?' ) ) + args; QgsDebugMsgLevel( QStringLiteral( "Get %1 (after laundering)" ).arg( modifiedUrlString ), 4 ); modifiedUrl = QUrl::fromLocalFile( modifiedUrlString ); } QgsDebugMsgLevel( QStringLiteral( "Calling: %1" ).arg( modifiedUrl.toDisplayString( ) ), 4 ); QNetworkRequest request( modifiedUrl ); if ( !mUri.auth().setAuthorization( request ) ) { mErrorCode = QgsWfsRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); return false; } if ( cache ) { request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, forceRefresh ? QNetworkRequest::AlwaysNetwork : QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); } QWaitCondition waitCondition; QMutex waitConditionMutex; bool threadFinished = false; bool success = false; std::function<void()> downloaderFunction = [ this, request, synchronous, &waitConditionMutex, &waitCondition, &threadFinished, &success ]() { if ( QThread::currentThread() != QgsApplication::instance()->thread() ) QgsNetworkAccessManager::instance( Qt::DirectConnection ); success = true; mReply = QgsNetworkAccessManager::instance()->get( request ); mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT ); if ( !mUri.auth().setAuthorizationReply( mReply ) ) { mErrorCode = QgsWfsRequest::NetworkError; mErrorMessage = errorMessageFailedAuth(); QgsMessageLog::logMessage( mErrorMessage, tr( "WFS" ) ); waitCondition.wakeAll(); success = false; } else { // We are able to use direct connection here, because we // * either run on the thread mReply lives in, so DirectConnection is standard and safe anyway // * or the owner thread of mReply is currently not doing anything because it's blocked in future.waitForFinished() (if it is the main thread) connect( mReply, &QNetworkReply::finished, this, &QgsWfsRequest::replyFinished, Qt::DirectConnection ); connect( mReply, &QNetworkReply::downloadProgress, this, &QgsWfsRequest::replyProgress, Qt::DirectConnection ); if ( synchronous ) { auto resumeMainThread = [&waitConditionMutex, &waitCondition]() { waitConditionMutex.lock(); waitCondition.wakeAll(); waitConditionMutex.unlock(); waitConditionMutex.lock(); waitCondition.wait( &waitConditionMutex ); waitConditionMutex.unlock(); }; connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::authenticationRequired, this, resumeMainThread, Qt::DirectConnection ); connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::proxyAuthenticationRequired, this, resumeMainThread, Qt::DirectConnection ); #ifndef QT_NO_SSL connect( QgsNetworkAccessManager::instance(), &QgsNetworkAccessManager::sslErrors, this, resumeMainThread, Qt::DirectConnection ); #endif QEventLoop loop; connect( this, &QgsWfsRequest::downloadFinished, &loop, &QEventLoop::quit, Qt::DirectConnection ); loop.exec(); } } waitConditionMutex.lock(); threadFinished = true; waitCondition.wakeAll(); waitConditionMutex.unlock(); }; if ( synchronous && QThread::currentThread() == QApplication::instance()->thread() ) { std::unique_ptr<DownloaderThread> downloaderThread = qgis::make_unique<DownloaderThread>( downloaderFunction ); downloaderThread->start(); while ( true ) { waitConditionMutex.lock(); if ( threadFinished ) { waitConditionMutex.unlock(); break; } waitCondition.wait( &waitConditionMutex ); // If the downloader thread wakes us (the main thread) up and is not yet finished // he needs the authentication to run. // The processEvents() call gives the auth manager the chance to show a dialog and // once done with that, we can wake the downloaderThread again and continue the download. if ( !threadFinished ) { waitConditionMutex.unlock(); QgsApplication::instance()->processEvents(); waitConditionMutex.lock(); waitCondition.wakeAll(); waitConditionMutex.unlock(); } else { waitConditionMutex.unlock(); } } // wait for thread to gracefully exit downloaderThread->wait(); } else { downloaderFunction(); } return success && mErrorMessage.isEmpty(); }