#include #include #include #include #include #include #include #include #include #include #include #include class Downloader::p_Downloader { using login_pair=QPair; QNetworkAccessManager manager; QHash auth; QReadWriteLock pending_requests_lock; QHash pending_requests; QNetworkRequest buildRequest(const QString& url, const QString &user="", const QString &passwd="") { QNetworkRequest request; request.setUrl(QUrl(url)); request.setRawHeader("User-Agent", "SciQLop 1.0"); if(user!="" and passwd!="") { //might grow quickly since we can have tons of URLs for the same host auth[url]=login_pair(user,passwd); QString login = "Basic "+user+":"+passwd; request.setRawHeader("Authorization",login.toLocal8Bit()); } return request; } public: explicit p_Downloader() { auto login_bambda = [this](QNetworkReply * reply, QAuthenticator * authenticator) { if(auth.contains(reply->url().toString())) { auto login = auth[reply->url().toString()]; authenticator->setUser(login.first); authenticator->setPassword(login.second); } }; QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda); } Response get(const QString& url, const QString &user="", const QString &passwd="") { QNetworkRequest request = buildRequest(url, user, passwd); QNetworkReply *reply = manager.get(request); while (!reply->isFinished()) { QCoreApplication::processEvents(); QThread::usleep(10000); } QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); Response resp = Response(reply->readAll(), status_code.toInt()); delete reply; if(user!="" and passwd!="") auth.remove(url); return resp; } QUuid getAsync(const QString &url, std::function callback, const QString &user, const QString &passwd) { auto uuid = QUuid::createUuid(); QNetworkRequest request = buildRequest(url, user, passwd); QNetworkReply *reply = manager.get(request); auto callback_wrapper = [url, uuid, callback, this](){ QNetworkReply* reply; { QWriteLocker locker(&pending_requests_lock); reply = pending_requests.take(uuid); } QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); Response resp = Response(reply->readAll(), status_code.toInt()); auth.remove(url); delete reply; callback(uuid, resp); }; QObject::connect(reply, &QNetworkReply::finished, callback_wrapper); { QWriteLocker locker(&pending_requests_lock); pending_requests[uuid] = reply; } return uuid; } bool downloadFinished(QUuid uuid) { QReadLocker locker(&pending_requests_lock); if(pending_requests.contains(uuid)) { auto req = pending_requests[uuid]; return req->isFinished(); } return true; } }; Response Downloader::get(const QString &url, const QString &user, const QString &passwd) { return Downloader::instance().impl->get(url, user, passwd); } QUuid Downloader::getAsync(const QString &url, std::function callback, const QString &user, const QString &passwd) { return Downloader::instance().impl->getAsync(url, callback, user, passwd); } bool Downloader::downloadFinished(QUuid uuid) { return Downloader::instance().impl->downloadFinished(uuid); } Downloader::Downloader() :impl(spimpl::make_unique_impl()) { }