Warning, file /multimedia/amarok/src/network/NetworkAccessManagerProxy.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Urs Wolfer <uwolfer@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #ifndef AMAROK_NETWORKACCESSMANAGERPROXY 0018 #define AMAROK_NETWORKACCESSMANAGERPROXY 0019 0020 #include "amarok_export.h" 0021 #include <config.h> 0022 #include "core/support/Debug.h" 0023 0024 #include <KIO/AccessManager> 0025 0026 #include <QNetworkReply> 0027 #include <QPointer> 0028 #include <QUrl> 0029 #include <QThread> 0030 #include <QTimer> 0031 0032 0033 class NetworkAccessManagerProxy; 0034 #ifdef DEBUG_BUILD_TYPE 0035 class NetworkAccessViewer; 0036 #endif // DEBUG_BUILD_TYPE 0037 0038 namespace The 0039 { 0040 AMAROK_EXPORT NetworkAccessManagerProxy *networkAccessManager(); 0041 } 0042 0043 class AMAROK_EXPORT NetworkAccessManagerProxy : public KIO::Integration::AccessManager 0044 { 0045 Q_OBJECT 0046 0047 public: 0048 static NetworkAccessManagerProxy *instance(); 0049 static void destroy(); 0050 ~NetworkAccessManagerProxy() override; 0051 0052 struct Error 0053 { 0054 QNetworkReply::NetworkError code; 0055 QString description; 0056 }; 0057 0058 /** 0059 * Gets the contents of the target @p url. It is a convenience wrapper 0060 * around QNetworkAccessManager::get() where the user supplies a 0061 * slot @p method to be called when the content is retrieved. 0062 * NOTE: On redirects requestRedirected is emitted. 0063 * 0064 * @param url the url to get the content from. 0065 * @param receiver the receiver object to call @p method on. 0066 * @param method the method to call when content is retrieved. 0067 * @param type the Qt::ConnectionType used for calling the @p method. 0068 * @return a QNetworkReply object for custom monitoring. 0069 */ 0070 template<typename Return, typename Object, typename... Args> 0071 QNetworkReply *getData( const QUrl &url, Object *receiver, Return ( Object::*method )( Args... ), 0072 Qt::ConnectionType type = Qt::AutoConnection ) 0073 { 0074 if( !url.isValid() ) 0075 { 0076 const QMetaObject *mo = receiver->metaObject(); 0077 debug() << QStringLiteral( "Error: URL '%1' is invalid (from %2)" ).arg( url.url(), mo->className() ); 0078 return nullptr; 0079 } 0080 0081 QNetworkReply *r = get( QNetworkRequest(url) ); 0082 m_urlMap.insert( url, r ); 0083 auto lambda = [this, r, receiver, method, type] () 0084 { 0085 replyFinished( r, QPointer<Object>( receiver ), method, type ); 0086 }; 0087 connect( r, &QNetworkReply::finished, this, lambda ); 0088 return r; 0089 } 0090 0091 int abortGet( const QUrl &url ); 0092 int abortGet( const QList<QUrl> &urls ); 0093 0094 /** 0095 * Gets the URL to which a server redirects the request. 0096 * An empty QUrl will be returned if the request was not redirected. 0097 * 0098 * @param reply The QNetworkReply which contains all information about 0099 * the reply from the server. 0100 * 0101 * @return The URL to which the server redirected the request or an empty 0102 * URL if there was no redirect. 0103 */ 0104 QUrl getRedirectUrl( QNetworkReply *reply ); 0105 0106 #ifdef DEBUG_BUILD_TYPE 0107 NetworkAccessViewer *networkAccessViewer(); 0108 void setNetworkAccessViewer( NetworkAccessViewer *viewer ); 0109 #endif // DEBUG_BUILD_TYPE 0110 0111 Q_SIGNALS: 0112 void requestRedirectedUrl( const QUrl &sourceUrl, const QUrl &targetUrl ); 0113 void requestRedirectedReply( QNetworkReply* oldReply, QNetworkReply *newReply ); 0114 0115 public Q_SLOTS: 0116 void slotError( QObject *reply ); 0117 0118 protected: 0119 QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, 0120 QIODevice *outgoingData = nullptr) override; 0121 0122 private: 0123 NetworkAccessManagerProxy( QObject *parent = nullptr ); 0124 0125 template <typename Return, typename Object, typename... Args> 0126 void replyFinished( QNetworkReply *reply, QPointer<Object> receiver, Return ( Object::*method )( Args... ), Qt::ConnectionType type ) 0127 { 0128 if( !reply || !receiver ) 0129 return; 0130 0131 QUrl url = reply->request().url(); 0132 QByteArray data = reply->readAll(); 0133 data.detach(); // detach so the bytes are not deleted before methods are invoked 0134 0135 // There may have been a redirect. 0136 QUrl redirectUrl = getRedirectUrl( reply ); 0137 0138 // Check if there's no redirect. 0139 if( redirectUrl.isEmpty() ) 0140 { 0141 Error err = { reply->error(), reply->errorString() }; 0142 0143 if( type == Qt::AutoConnection ) 0144 { 0145 if( QThread::currentThread() == receiver->thread() ) 0146 type = Qt::DirectConnection; 0147 else 0148 type = Qt::QueuedConnection; 0149 } 0150 0151 if( type == Qt::DirectConnection ) 0152 ( receiver->*method )( url, data, err ); 0153 else 0154 { 0155 auto lambda = [receiver, method, url, data, err] () 0156 { 0157 ( receiver->*method )( url, data, err ); 0158 }; 0159 QTimer::singleShot( 0, receiver, lambda ); 0160 } 0161 } 0162 else 0163 { 0164 debug() << "the server is redirecting the request to: " << redirectUrl; 0165 0166 // Let's try to fetch the data again, but this time from the new url. 0167 QNetworkReply *newReply = getData( redirectUrl, receiver.data(), method, type ); 0168 0169 Q_EMIT requestRedirectedUrl( url, redirectUrl ); 0170 Q_EMIT requestRedirectedReply( reply, newReply ); 0171 } 0172 0173 reply->deleteLater(); 0174 } 0175 0176 static NetworkAccessManagerProxy *s_instance; 0177 0178 QMultiHash<QUrl, QNetworkReply*> m_urlMap; 0179 QString m_userAgent; 0180 0181 #ifdef DEBUG_BUILD_TYPE 0182 NetworkAccessViewer *m_viewer; 0183 #endif // DEBUG_BUILD_TYPE 0184 0185 Q_DISABLE_COPY( NetworkAccessManagerProxy ) 0186 }; 0187 0188 Q_DECLARE_METATYPE( NetworkAccessManagerProxy::Error ) 0189 #endif // AMAROK_NETWORKACCESSMANAGERPROXY