2016-01-28 3 views
-1

Я пытался адаптировать небольшую программу Qt, предназначенную для загрузки одного файла с сервера. Все, что он делает (на данный момент), запрашивает URL-адрес, затем он загружает его.Qt authenticationRequired over HTTPS и файл загрузки

Что бы я хотел сделать, прежде чем приступить к более сложной работе, это заставить его работать с аутентификацией. После прочтения документации и поиска нескольких примеров с использованием классов QNetworkAccessManager и QAuthenticator я попытался ее модифицировать. Но по какой-то причине, когда я правильно связываю сигнал authenticationRequired с моим экземпляром QNetworkAccessManager с пользовательским слотом и устанавливаю имя пользователя/пароль для объекта QAuthenticator, кажется, что сигнал, удостоверяющий подлинность, никогда не отправляется (добавление qDebug внутри слота. (я планирую добавить позже, когда я получу это для работы).

Я проверял, что я поставил connect() перед вызовом get() и попробовал несколько мест для него: попытался помещать создание QNetworkAccessManager в конструктор моего класса, а затем перед использованием get(). Но ничего не работает, поскольку все, что я получаю при попытке загрузки, требующей auth, - это «запрещенный» код ошибки. Поскольку я никогда не работал с Qt Network, я не уверен, что я сделал что-то не так.

Вот мой полный код

//HttpDownload.h 
#ifndef HTTPDOWNLOAD_H 
#define HTTPDOWNLOAD_H 

#include <QDialog> 
#include <QNetworkAccessManager> 
#include <QNetworkRequest> 
#include <QNetworkReply> 
#include <QUrl> 
#include <QProgressDialog> 
#include <QFile> 
#include <QFileInfo> 
#include <QDir> 
#include <QMessageBox> 
#include <QDebug> 
#include <QAuthenticator> 

namespace Ui { 
class HttpDownload; 
} 

class HttpDownload : public QDialog 
{ 
    Q_OBJECT 

public: 
    explicit HttpDownload(QWidget *parent = 0); 
    ~HttpDownload(); 

public: 
    void startRequest(QUrl url); 
private slots: 
    void on_downloadButton_clicked(); 

    void on_quitButton_clicked(); 

    void on_urlEdit_returnPressed(); 

    // slot for readyRead() signal 
    void httpReadyRead(); 

    // slot for finished() signal from reply 
    void httpDownloadFinished(); 

    // slot for downloadProgress() 
    void updateDownloadProgress(qint64, qint64); 

    void enableDownloadButton(); 
    void cancelDownload(); 
    void authRequired(QNetworkReply*, QAuthenticator*); // Auth slot 
private: 
    Ui::HttpDownload *ui; 
    QUrl url; 
    QNetworkAccessManager *manager; 
    QNetworkReply *reply; 
    QProgressDialog *progressDialog; 
    QFile *file; 
    bool httpRequestAborted; 
    qint64 fileSize; 

}; 

#endif // HTTPDOWNLOAD_H 

//HttpDownload.cpp 
#include "httpdownload.h" 
#include "ui_httpdownload.h" 

HttpDownload::HttpDownload(QWidget *parent) : 
    QDialog(parent), 
    ui(new Ui::HttpDownload) 
{ 
    ui->setupUi(this); 
    ui->urlEdit->setText(HTTPS_URL); 
    ui->statusLabel->setWordWrap(true); 
    ui->downloadButton->setDefault(true); 
    ui->quitButton->setAutoDefault(false); 

    progressDialog = new QProgressDialog(this); 

    connect(ui->urlEdit, 
      SIGNAL(textChanged(QString)), 
      this, 
      SLOT(enableDownloadButton()) 
     ); 
    connect(progressDialog, 
      SIGNAL(canceled()), 
      this, 
      SLOT(cancelDownload()) 
     ); 
} 

HttpDownload::~HttpDownload() 
{ 
    delete ui; 
} 

// Auth slot 
void HttpDownload::authRequired(QNetworkReply *reply, QAuthenticator *ator) 
{ 
    qDebug() << "auth Alert"; 
    qDebug() << reply->readAll(); // this is just to see what we received 
    qDebug() << Q_FUNC_INFO << ator->realm(); 
    ator->setUser(QString(USERNAME)); 
    ator->setPassword(QString(PASSWORD)); 
} 

void HttpDownload::on_downloadButton_clicked() 
{ 
// manager = new QNetworkAccessManager(this); 

    // get url 
    url = (ui->urlEdit->text()); 

    QFileInfo fileInfo(url.path()); 
    QString fileName = fileInfo.fileName(); 

    if (fileName.isEmpty()) 
     fileName = "index.html"; 

    if (QFile::exists(fileName)) { 
     if (QMessageBox::question(this, tr("HTTP"), 
       tr("There already exists a file called %1 in " 
       "the current directory. Overwrite?").arg(fileName), 
       QMessageBox::Yes|QMessageBox::No, QMessageBox::No) 
       == QMessageBox::No) 
       return; 
     QFile::remove(fileName); 
    } 

    file = new QFile(fileName); 
    if (!file->open(QIODevice::WriteOnly)) { 
     QMessageBox::information(this, tr("HTTP"), 
         tr("Unable to save the file %1: %2.") 
         .arg(fileName).arg(file->errorString())); 
     delete file; 
     file = 0; 
     return; 
    } 

    // used for progressDialog 
    // This will be set true when canceled from progress dialog 
    httpRequestAborted = false; 

    progressDialog->setWindowTitle(tr("HTTP")); 
    progressDialog->setLabelText(tr("Downloading %1.").arg(fileName)); 

    // download button disabled after requesting download 
    ui->downloadButton->setEnabled(false); 

    startRequest(url); 
} 

void HttpDownload::httpReadyRead() 
{ 
    // this slot gets called every time the QNetworkReply has new data. 
    // We read all of its new data and write it into the file. 
    // That way we use less RAM than when reading it at the finished() 
    // signal of the QNetworkReply 
    if (file) 
     file->write(reply->readAll()); 
} 

void HttpDownload::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) 
{ 
    if (httpRequestAborted) 
     return; 

    progressDialog->setMaximum(totalBytes); 
    progressDialog->setValue(bytesRead); 
} 

void HttpDownload::on_quitButton_clicked() 
{ 
    this->close(); 
} 

void HttpDownload::on_urlEdit_returnPressed() 
{ 
    on_downloadButton_clicked(); 
} 

void HttpDownload::enableDownloadButton() 
{ 
    ui->downloadButton->setEnabled(!(ui->urlEdit->text()).isEmpty()); 
} 

// During the download progress, it can be canceled 
void HttpDownload::cancelDownload() 
{ 
    ui->statusLabel->setText(tr("Download canceled.")); 
    httpRequestAborted = true; 
    reply->abort(); 
    ui->downloadButton->setEnabled(true); 
} 

// When download finished or canceled, this will be called 
void HttpDownload::httpDownloadFinished() 
{ 
    // when canceled 
    if (httpRequestAborted) { 
     if (file) { 
      file->close(); 
      file->remove(); 
      delete file; 
      file = 0; 
     } 
     reply->deleteLater(); 
     progressDialog->hide(); 
     return; 
    } 

    // download finished normally 
    progressDialog->hide(); 
    file->flush(); 
    file->close(); 

    // get redirection url 
    QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); 
    if (reply->error()) { 
     file->remove(); 
     QMessageBox::information(this, tr("HTTP"), 
           tr("Download failed: %1.") 
           .arg(reply->errorString())); 
     ui->downloadButton->setEnabled(true); 
    } else if (!redirectionTarget.isNull()) { 
     QUrl newUrl = url.resolved(redirectionTarget.toUrl()); 
     if (QMessageBox::question(this, tr("HTTP"), 
            tr("Redirect to %1 ?").arg(newUrl.toString()), 
            QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { 
      url = newUrl; 
      reply->deleteLater(); 
      file->open(QIODevice::WriteOnly); 
      file->resize(0); 
      startRequest(url); 
      return; 
     } 
    } else { 
     QString fileName = QFileInfo(QUrl(ui->urlEdit->text()).path()).fileName(); 
     ui->statusLabel->setText(tr("Downloaded %1 to %2.").arg(fileName).arg(QDir::currentPath())); 
     ui->downloadButton->setEnabled(true); 
    } 

    reply->deleteLater(); 
    reply = 0; 
    delete file; 
    file = 0; 
    manager = 0; 
} 

// This will be called when download button is clicked 
void HttpDownload::startRequest(QUrl url) 
{ 
    qDebug() << "Begin download"; 

    manager = new QNetworkAccessManager(this); 

    connect(manager, 
     SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), 
     SLOT(authRequired(QNetworkReply*,QAuthenticator*)) 
     ); 

    // get() method posts a request 
    // to obtain the contents of the target request 
    // and returns a new QNetworkReply object 
    // opened for reading which emits 
    // the readyRead() signal whenever new data arrives. 
    reply = manager->get(QNetworkRequest(url)); 

    // Whenever more data is received from the network, 
    // this readyRead() signal is emitted 
    connect(reply, SIGNAL(readyRead()), 
      this, SLOT(httpReadyRead())); 

    // Also, downloadProgress() signal is emitted when data is received 
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)), 
      this, SLOT(updateDownloadProgress(qint64,qint64))); 

    // This signal is emitted when the reply has finished processing. 
    // After this signal is emitted, 
    // there will be no more updates to the reply's data or metadata. 
    connect(reply, SIGNAL(finished()), 
      this, SLOT(httpDownloadFinished())); 
} 

//main.cpp 
#include "httpdownload.h" 
#include <QApplication> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    HttpDownload w; 
    w.setWindowTitle("Http Download"); 
    w.show(); 

    return a.exec(); 
} 

ответ

-1

Подключается только телеграфировать вызовы, которые случатся в будущем. Вы должны делать все свои подключения перед любыми вызовами, которые могут вызвать их. После этого, если событие auth никогда не встречается, это означает, что причиной является хост, а не ваш код. Ваш подход к auth выглядит корректно. Попробуйте проследить его с помощью Fiddler или чего-то подобного.

+0

Я подозревал, что хозяин первым, но так как я был в состоянии загрузить файлы (более HTTPS с базовой аутентификацией из того же хоста) с помощью PHP, так что я предполагаю, что это может Это не так. –

-1

Я думаю, что вы не получили этот перед SLOT!

connect(manager, 
     SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), 
     SLOT(authRequired(QNetworkReply*,QAuthenticator*)) 
     ); 

должен быть

connect(manager, 
      SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), 
      this, SLOT(authRequired(QNetworkReply*,QAuthenticator*)) 
      ); 
+0

Наличие ** этого ** (или его отсутствия) имеет тот же эффект: сигнал authenticationRequired() никогда не отправляется. –