mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-09-27 15:46:51 -04:00
e61f5fa38f
It seems that the OpenSSL version on some systems is not capable of correctly handling intermediate certificates for some sites. These sites include SourceForge which we use for serving sample files. This change adds a global handler for QNAM SSL errors with the option to ignore them at the users discretion. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7359 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
266 lines
7.8 KiB
C++
266 lines
7.8 KiB
C++
#include "RemoteFile.hpp"
|
|
|
|
#include <utility>
|
|
|
|
#include <QNetworkAccessManager>
|
|
#include <QNetworkReply>
|
|
#include <QDir>
|
|
#include <QByteArray>
|
|
|
|
#include "moc_RemoteFile.cpp"
|
|
|
|
RemoteFile::RemoteFile (ListenerInterface * listener, QNetworkAccessManager * network_manager
|
|
, QString const& local_file_path, QObject * parent)
|
|
: QObject {parent}
|
|
, listener_ {listener}
|
|
, network_manager_ {network_manager}
|
|
, local_file_ {local_file_path}
|
|
, reply_ {nullptr}
|
|
, is_valid_ {false}
|
|
, redirect_count_ {0}
|
|
, file_ {local_file_path}
|
|
{
|
|
local_file_.setCaching (false);
|
|
}
|
|
|
|
void RemoteFile::local_file_path (QString const& name)
|
|
{
|
|
QFileInfo new_file {name};
|
|
new_file.setCaching (false);
|
|
if (new_file != local_file_)
|
|
{
|
|
if (local_file_.exists ())
|
|
{
|
|
QFile file {local_file_.absoluteFilePath ()};
|
|
if (!file.rename (new_file.absoluteFilePath ()))
|
|
{
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot rename file:\n\"%1\"\nto: \"%2\"\nError(%3): %4")
|
|
.arg (file.fileName ())
|
|
.arg (new_file.absoluteFilePath ())
|
|
.arg (file.error ())
|
|
.arg (file.errorString ()));
|
|
}
|
|
}
|
|
std::swap (local_file_, new_file);
|
|
}
|
|
}
|
|
|
|
bool RemoteFile::local () const
|
|
{
|
|
auto is_local = (reply_ && !reply_->isFinished ()) || local_file_.exists ();
|
|
if (is_local)
|
|
{
|
|
auto size = local_file_.size ();
|
|
listener_->download_progress (size, size);
|
|
listener_->download_finished (true);
|
|
}
|
|
else
|
|
{
|
|
listener_->download_progress (-1, 0);
|
|
}
|
|
return is_local;
|
|
}
|
|
|
|
bool RemoteFile::sync (QUrl const& url, bool local, bool force)
|
|
{
|
|
if (local)
|
|
{
|
|
if (!reply_ || reply_->isFinished ()) // not active download
|
|
{
|
|
if (force || !local_file_.exists () || url != url_)
|
|
{
|
|
url_ = url;
|
|
redirect_count_ = 0;
|
|
Q_ASSERT (!is_valid_);
|
|
download (url_);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (reply_ && reply_->isRunning ())
|
|
{
|
|
reply_->abort ();
|
|
}
|
|
if (local_file_.exists ())
|
|
{
|
|
auto path = local_file_.absoluteDir ();
|
|
if (path.remove (local_file_.fileName ()))
|
|
{
|
|
listener_->download_progress (-1, 0);
|
|
}
|
|
else
|
|
{
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot delete file:\n\"%1\"")
|
|
.arg (local_file_.absoluteFilePath ()));
|
|
return false;
|
|
}
|
|
path.rmpath (".");
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void RemoteFile::download (QUrl const& url)
|
|
{
|
|
if (QNetworkAccessManager::Accessible != network_manager_->networkAccessible ()) {
|
|
// try and recover network access for QNAM
|
|
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
|
|
}
|
|
|
|
QNetworkRequest request {url};
|
|
request.setRawHeader ("User-Agent", "WSJT Sample Downloader");
|
|
request.setOriginatingObject (this);
|
|
|
|
// this blocks for a second or two the first time it is used on
|
|
// Windows - annoying
|
|
if (!is_valid_)
|
|
{
|
|
reply_ = network_manager_->head (request);
|
|
}
|
|
else
|
|
{
|
|
reply_ = network_manager_->get (request);
|
|
}
|
|
|
|
connect (reply_, &QNetworkReply::finished, this, &RemoteFile::reply_finished);
|
|
connect (reply_, &QNetworkReply::readyRead, this, &RemoteFile::store);
|
|
connect (reply_, &QNetworkReply::downloadProgress
|
|
, [this] (qint64 bytes_received, qint64 total_bytes) {
|
|
// report progress of wanted file
|
|
if (is_valid_)
|
|
{
|
|
listener_->download_progress (bytes_received, total_bytes);
|
|
}
|
|
});
|
|
}
|
|
|
|
void RemoteFile::abort ()
|
|
{
|
|
if (reply_ && reply_->isRunning ())
|
|
{
|
|
reply_->abort ();
|
|
}
|
|
}
|
|
|
|
void RemoteFile::reply_finished ()
|
|
{
|
|
auto saved_reply = reply_;
|
|
auto redirect_url = reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ();
|
|
if (!redirect_url.isEmpty ())
|
|
{
|
|
if (listener_->redirect_request (redirect_url))
|
|
{
|
|
if (++redirect_count_ < 10) // maintain sanity
|
|
{
|
|
// follow redirect
|
|
download (reply_->url ().resolved (redirect_url));
|
|
}
|
|
else
|
|
{
|
|
listener_->download_finished (false);
|
|
listener_->error (tr ("Network Error")
|
|
, tr ("Too many redirects: %1")
|
|
.arg (redirect_url.toDisplayString ()));
|
|
is_valid_ = false; // reset
|
|
}
|
|
}
|
|
else
|
|
{
|
|
listener_->download_finished (false);
|
|
listener_->error (tr ("Network Error")
|
|
, tr ("Redirect not followed: %1")
|
|
.arg (redirect_url.toDisplayString ()));
|
|
is_valid_ = false; // reset
|
|
}
|
|
}
|
|
else if (reply_->error () != QNetworkReply::NoError)
|
|
{
|
|
file_.cancelWriting ();
|
|
file_.commit ();
|
|
listener_->download_finished (false);
|
|
is_valid_ = false; // reset
|
|
// report errors that are not due to abort
|
|
if (QNetworkReply::OperationCanceledError != reply_->error ())
|
|
{
|
|
listener_->error (tr ("Network Error"), reply_->errorString ());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto path = QFileInfo {file_.fileName ()}.absoluteDir ();
|
|
if (is_valid_ && !file_.commit ())
|
|
{
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot commit changes to:\n\"%1\"")
|
|
.arg (file_.fileName ()));
|
|
path.rmpath ("."); // tidy empty directories
|
|
listener_->download_finished (false);
|
|
is_valid_ = false; // reset
|
|
}
|
|
else
|
|
{
|
|
if (!is_valid_)
|
|
{
|
|
// now get the body content
|
|
is_valid_ = true;
|
|
download (reply_->url () .resolved (redirect_url));
|
|
}
|
|
else
|
|
{
|
|
listener_->download_finished (true);
|
|
is_valid_ = false; // reset
|
|
}
|
|
}
|
|
}
|
|
if (reply_->isFinished ()) reply_ = nullptr;
|
|
disconnect (saved_reply);
|
|
saved_reply->deleteLater (); // finished with QNetworkReply
|
|
}
|
|
|
|
void RemoteFile::store ()
|
|
{
|
|
if (is_valid_)
|
|
{
|
|
if (!file_.isOpen ())
|
|
{
|
|
// create temporary file in the final location
|
|
auto path = QFileInfo {file_.fileName ()}.absoluteDir ();
|
|
if (path.mkpath ("."))
|
|
{
|
|
if (!file_.open (QSaveFile::WriteOnly))
|
|
{
|
|
abort ();
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot open file:\n\"%1\"\nError(%2): %3")
|
|
.arg (path.path ())
|
|
.arg (file_.error ())
|
|
.arg (file_.errorString ()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
abort ();
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot make path:\n\"%1\"")
|
|
.arg (path.path ()));
|
|
}
|
|
}
|
|
if (file_.write (reply_->read (reply_->bytesAvailable ())) < 0)
|
|
{
|
|
abort ();
|
|
listener_->error (tr ("File System Error")
|
|
, tr ("Cannot write to file:\n\"%1\"\nError(%2): %3")
|
|
.arg (file_.fileName ())
|
|
.arg (file_.error ())
|
|
.arg (file_.errorString ()));
|
|
}
|
|
}
|
|
}
|