Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsblockingnetworkrequest.h 3 : : --------------------------- 4 : : begin : November 2018 5 : : copyright : (C) 2018 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : #ifndef QGSBLOCKINGNETWORKREQUEST_H 16 : : #define QGSBLOCKINGNETWORKREQUEST_H 17 : : 18 : : #include "qgis_core.h" 19 : : #include "qgsnetworkreply.h" 20 : : #include "qgsfeedback.h" 21 : : #include <QThread> 22 : : #include <QObject> 23 : : #include <functional> 24 : : #include <QPointer> 25 : : 26 : : class QNetworkRequest; 27 : : class QNetworkReply; 28 : : 29 : : /** 30 : : * \brief A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy 31 : : * and authentication settings. 32 : : * 33 : : * This class should be used whenever a blocking network request is required. Unlike implementations 34 : : * which rely on QApplication::processEvents() or creation of a QEventLoop, this class is completely 35 : : * thread safe and can be used on either the main thread or background threads without issue. 36 : : * 37 : : * Redirects are automatically handled by the class. 38 : : * 39 : : * After completion of a request, the reply content should be retrieved by calling getReplyContent(). 40 : : * This method returns a QgsNetworkReplyContent container, which is safe and cheap to copy and pass 41 : : * between threads without issue. 42 : : * 43 : : * \ingroup core 44 : : * \since QGIS 3.6 45 : : */ 46 : : class CORE_EXPORT QgsBlockingNetworkRequest : public QObject 47 : : { 48 : 0 : Q_OBJECT 49 : : public: 50 : : 51 : : //! Error codes 52 : : enum ErrorCode 53 : : { 54 : : NoError, //!< No error was encountered 55 : : NetworkError, //!< A network error occurred 56 : : TimeoutError, //!< Timeout was reached before a reply was received 57 : : ServerExceptionError, //!< An exception was raised by the server 58 : : }; 59 : : 60 : : //! Constructor for QgsBlockingNetworkRequest 61 : : explicit QgsBlockingNetworkRequest(); 62 : : 63 : : ~QgsBlockingNetworkRequest() override; 64 : : 65 : : /** 66 : : * Performs a "get" operation on the specified \a request. 67 : : * 68 : : * If \a forceRefresh is FALSE then previously cached replies may be used for the request. If 69 : : * it is set to TRUE then a new query is always performed. 70 : : * 71 : : * If an authCfg() has been set, then any authentication configuration required will automatically be applied to 72 : : * \a request. There is no need to manually apply the authentication to the request prior to calling 73 : : * this method. 74 : : * 75 : : * The optional \a feedback argument can be used to abort ongoing requests. 76 : : * 77 : : * The method will return NoError if the get operation was successful. The contents of the reply can be retrieved 78 : : * by calling reply(). 79 : : * 80 : : * If an error was encountered then a specific ErrorCode will be returned, and a detailed error message 81 : : * can be retrieved by calling errorMessage(). 82 : : * 83 : : * \see post() 84 : : */ 85 : : ErrorCode get( QNetworkRequest &request, bool forceRefresh = false, QgsFeedback *feedback = nullptr ); 86 : : 87 : : /** 88 : : * Performs a "post" operation on the specified \a request, using the given \a data. 89 : : * 90 : : * If \a forceRefresh is FALSE then previously cached replies may be used for the request. If 91 : : * it is set to TRUE then a new query is always performed. 92 : : * 93 : : * If an authCfg() has been set, then any authentication configuration required will automatically be applied to 94 : : * \a request. There is no need to manually apply the authentication to the request prior to calling 95 : : * this method. 96 : : * 97 : : * The optional \a feedback argument can be used to abort ongoing requests. 98 : : * 99 : : * The method will return NoError if the get operation was successful. The contents of the reply can be retrieved 100 : : * by calling reply(). 101 : : * 102 : : * If an error was encountered then a specific ErrorCode will be returned, and a detailed error message 103 : : * can be retrieved by calling errorMessage(). 104 : : * 105 : : * \see get() 106 : : */ 107 : : ErrorCode post( QNetworkRequest &request, const QByteArray &data, bool forceRefresh = false, QgsFeedback *feedback = nullptr ); 108 : : 109 : : /** 110 : : * Performs a "head" operation on the specified \a request. 111 : : * 112 : : * If \a forceRefresh is FALSE then previously cached replies may be used for the request. If 113 : : * it is set to TRUE then a new query is always performed. 114 : : * 115 : : * If an authCfg() has been set, then any authentication configuration required will automatically be applied to 116 : : * \a request. There is no need to manually apply the authentication to the request prior to calling 117 : : * this method. 118 : : * 119 : : * The optional \a feedback argument can be used to abort ongoing requests. 120 : : * 121 : : * The method will return NoError if the get operation was successful. The contents of the reply can be retrieved 122 : : * by calling reply(). 123 : : * 124 : : * If an error was encountered then a specific ErrorCode will be returned, and a detailed error message 125 : : * can be retrieved by calling errorMessage(). 126 : : * 127 : : * \since 3.18 128 : : */ 129 : : ErrorCode head( QNetworkRequest &request, bool forceRefresh = false, QgsFeedback *feedback = nullptr ); 130 : : 131 : : /** 132 : : * Performs a "put" operation on the specified \a request, using the given \a data. 133 : : * 134 : : * If an authCfg() has been set, then any authentication configuration required will automatically be applied to 135 : : * \a request. There is no need to manually apply the authentication to the request prior to calling 136 : : * this method. 137 : : * 138 : : * The optional \a feedback argument can be used to abort ongoing requests. 139 : : * 140 : : * The method will return NoError if the get operation was successful. The contents of the reply can be retrieved 141 : : * by calling reply(). 142 : : * 143 : : * If an error was encountered then a specific ErrorCode will be returned, and a detailed error message 144 : : * can be retrieved by calling errorMessage(). 145 : : * 146 : : * \since 3.18 147 : : */ 148 : : ErrorCode put( QNetworkRequest &request, const QByteArray &data, QgsFeedback *feedback = nullptr ); 149 : : 150 : : /** 151 : : * Performs a "delete" operation on the specified \a request. 152 : : * 153 : : * If an authCfg() has been set, then any authentication configuration required will automatically be applied to 154 : : * \a request. There is no need to manually apply the authentication to the request prior to calling 155 : : * this method. 156 : : * 157 : : * The optional \a feedback argument can be used to abort ongoing requests. 158 : : * 159 : : * The method will return NoError if the get operation was successful. The contents of the reply can be retrieved 160 : : * by calling reply(). 161 : : * 162 : : * If an error was encountered then a specific ErrorCode will be returned, and a detailed error message 163 : : * can be retrieved by calling errorMessage(). 164 : : * 165 : : * \since 3.18 166 : : */ 167 : : ErrorCode deleteResource( QNetworkRequest &request, QgsFeedback *feedback = nullptr ); 168 : : 169 : : /** 170 : : * Returns the error message string, after a get() or post() request has been made.\ 171 : : */ 172 : 0 : QString errorMessage() const { return mErrorMessage; } 173 : : 174 : : /** 175 : : * Returns the content of the network reply, after a get() or post() request has been made. 176 : : */ 177 : 0 : QgsNetworkReplyContent reply() const { return mReplyContent; } 178 : : 179 : : /** 180 : : * Returns the authentication config id which will be used during the request. 181 : : * \see setAuthCfg() 182 : : */ 183 : : QString authCfg() const; 184 : : 185 : : /** 186 : : * Sets the authentication config id which should be used during the request. 187 : : * \see authCfg() 188 : : */ 189 : : void setAuthCfg( const QString &authCfg ); 190 : : 191 : : public slots: 192 : : 193 : : /** 194 : : * Aborts the network request immediately. 195 : : */ 196 : : void abort(); 197 : : 198 : : signals: 199 : : 200 : : /** 201 : : * Emitted when when data arrives during a request. 202 : : */ 203 : : void downloadProgress( qint64, qint64 ); 204 : : 205 : : /** 206 : : * Emitted once a request has finished downloading. 207 : : */ 208 : : void downloadFinished(); 209 : : 210 : : private slots: 211 : : void replyProgress( qint64, qint64 ); 212 : : void replyFinished(); 213 : : void requestTimedOut( QNetworkReply *reply ); 214 : : 215 : : private : 216 : : 217 : : enum Method 218 : : { 219 : : Get, 220 : : Post, 221 : : Head, 222 : : Put, 223 : : Delete 224 : : }; 225 : : 226 : : //! The reply to the request 227 : : QNetworkReply *mReply = nullptr; 228 : : 229 : : Method mMethod = Get; 230 : : QByteArray mPayloadData; 231 : : 232 : : //! Authentication configuration ID 233 : : QString mAuthCfg; 234 : : 235 : : //! The error message associated with the last error. 236 : : QString mErrorMessage; 237 : : 238 : : //! Error code 239 : : ErrorCode mErrorCode = NoError; 240 : : 241 : : QgsNetworkReplyContent mReplyContent; 242 : : 243 : : //! Whether the request is aborted. 244 : : bool mIsAborted = false; 245 : : 246 : : //! Whether to force refresh (i.e. issue a network request and not use cache) 247 : : bool mForceRefresh = false; 248 : : 249 : : //! Whether the request has timed-out 250 : : bool mTimedout = false; 251 : : 252 : : //! Whether we already received bytes 253 : : bool mGotNonEmptyResponse = false; 254 : : 255 : : int mExpirationSec = 30; 256 : : 257 : : QPointer< QgsFeedback > mFeedback; 258 : : 259 : : ErrorCode doRequest( Method method, QNetworkRequest &request, bool forceRefresh, QgsFeedback *feedback = nullptr ); 260 : : 261 : : QString errorMessageFailedAuth(); 262 : : 263 : : void sendRequestToNetworkAccessManager( const QNetworkRequest &request ); 264 : : }; 265 : : 266 : : ///@cond PRIVATE 267 : : #ifndef SIP_RUN 268 : : 269 : : class DownloaderThread : public QThread 270 : : { 271 : : Q_OBJECT 272 : : 273 : : public: 274 : 0 : DownloaderThread( const std::function<void()> &function, QObject *parent = nullptr ) 275 : 0 : : QThread( parent ) 276 : 0 : , mFunction( function ) 277 : 0 : { 278 : 0 : } 279 : : 280 : : void run() override 281 : : { 282 : : mFunction(); 283 : : } 284 : : 285 : : private: 286 : : std::function<void()> mFunction; 287 : : }; 288 : : 289 : : #endif 290 : : ///@endcond 291 : : 292 : : #endif // QGSBLOCKINGNETWORKREQUEST_H