QNetworkReply and 301 redirect
Asked Answered
K

2

12

I have a webviewer and only want it to only be able to access our webapps, to achieve this I have placed a php header which I look for in my Qt App. This works fine but with one exception and that's with 301 permanent moved status codes. Modern browsers redirect you automatically but putting a "/" at the end of the http request.

When a URL to our web app is entered it currently needs the trailing slash to be able to detect the headers but I want it to also get at that header even if they don't put a trailing slash.

Here is my current method to retrieve the header:

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    request.setUrl(url);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));

    request.setRawHeader("User-Agent", "CytoViewer 1.0");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/CytoViewer");
    QNetworkReply *reply = manager->get(request);
    reply->ignoreSslErrors();
    QEventLoop loop;

    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    qDebug() << "QLoop reply all: " << reply->readAll();
    qDebug() << "QLoop: " << reply->rawHeader("Cyto-Study-Manager");
    if(reply->rawHeader("OurWebApp") == "1"){
        //Header exists?(QEventLoop finish) Set arg[1]"url 'Found prouct: product header'"
        product = reply->rawHeader("Product");
        return true;
    } else {
        //Header doen't exist? Graceful error - not a valid PI product
        return false;
    }

To solve the problem of of hitting a 301 first I send two network requests, The first one hits the URL entered and check for a 301 if there is a 301 status code it get's the proposed url via the reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); method and returns that URL else if there is no status code then it simply returns the previous URL the user entered and then sends another network request to check the headers.

First request I send out to check status code:

QUrl MainWindow::networkRequest(QUrl checkUrl){
    qDebug() << "checkURL: " << checkUrl;
    //
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    request.setUrl(checkUrl);
    request.setRawHeader("User-Agent", "CytoViewer 1.0");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/CytoViewer");
    QNetworkReply *reply = manager->get(request);
    reply->ignoreSslErrors();
    QEventLoop checkLoop;
    connect(reply, SIGNAL(finished()), &checkLoop, SLOT(quit()));
    checkLoop.exec();
    //Check status code
    if (reply->error() == QNetworkReply::NoError) {
        int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        if(statusCode == 301) {
            QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
            return redirectUrl;
        }else {
            return checkUrl;
        }

    }
}

Long story short, I am sending two network requests, 1) To check for 301 2) To check for our app header.

Is there anyway to do this in one request? Am I missing a method that will do this redirection automatically?

Regards

Nathan

Kerf answered 11/2, 2013 at 9:33 Comment(0)
A
12

Apparently there is not.

There's an official HOWTO entry on https://web.archive.org/web/20141101060340/http://developer.nokia.com/community/wiki/Handling_an_HTTP_redirect_with_QNetworkAccessManager

Extraction from link above:

void QNAMRedirect::replyFinished(QNetworkReply* reply) {
    /*
     * Reply is finished!
     * We'll ask for the reply about the Redirection attribute
     * http://doc.trolltech.com/qnetworkrequest.html#Attribute-enum
     */
    QVariant possibleRedirectUrl =
             reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
 
    /* We'll deduct if the redirection is valid in the redirectUrl function */
    _urlRedirectedTo = this->redirectUrl(possibleRedirectUrl.toUrl(),
                                         _urlRedirectedTo);
 
    /* If the URL is not empty, we're being redirected. */
    if(!_urlRedirectedTo.isEmpty()) {
        QString text = QString("QNAMRedirect::replyFinished: Redirected to ")
                              .append(_urlRedirectedTo.toString());
        this->_textContainer->setText(text);
 
        /* We'll do another request to the redirection url. */
        this->_qnam->get(QNetworkRequest(_urlRedirectedTo));
    }
    else {
        /*
         * We weren't redirected anymore
         * so we arrived to the final destination...
         */
        QString text = QString("QNAMRedirect::replyFinished: Arrived to ")
                              .append(reply->url().toString());
        this->_textContainer->setText(text);
        /* ...so this can be cleared. */
        _urlRedirectedTo.clear();
    }
    /* Clean up. */
    reply->deleteLater();
}
 
QUrl QNAMRedirect::redirectUrl(const QUrl& possibleRedirectUrl,
                               const QUrl& oldRedirectUrl) const {
    QUrl redirectUrl;
    /*
     * Check if the URL is empty and
     * that we aren't being fooled into a infinite redirect loop.
     * We could also keep track of how many redirects we have been to
     * and set a limit to it, but we'll leave that to you.
     */
    if(!possibleRedirectUrl.isEmpty() &&
       possibleRedirectUrl != oldRedirectUrl) {
        redirectUrl = possibleRedirectUrl;
    }
    return redirectUrl;
}
Adebayo answered 11/2, 2013 at 9:58 Comment(3)
Thought there might not have been a way but wasn't sure if I was missing something somewhere, thanks for clearing that up @Adebayo :)Kerf
the link to the official HOWTO is broken :(Delighted
@DavidSánchez: Updated the comment to reflect this. Unfortunately the wiki content hasn't been moved before its deletion :(Adebayo
T
27

If you are using Qt 6 then skip reading this answer as auto redirection is a default behaviour

Old answer if you are not using Qt 6:

Auto redirection support was added to Qt 5.6 (QNetworkRequest::FollowRedirectsAttribute).

It's not enabled by default:

QNetworkRequest req(QUrl("https://example.com/"));
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
Tigges answered 3/4, 2016 at 14:33 Comment(5)
What do you mean old ? to me it is new. thanks for mentioning this, you saved my a**, I will update from 5.5 to 5.6 for this to work.Claypoole
Quick update here: QNetworkRequest::FollowRedirectsAttribute has been deprecated in favor of QNetworkRequest::RedirectPolicyAttribute (check possible values).Anarchy
I am using Qt6 and the redirect doesn't seem to be by default since it is not workingRedford
@Redford hmm weird are you sure its not trying to redirect from https to http?Tigges
@Tigges yeah, here is the link, you can test : dropbox.com/s/zqbxgw4owoteas0/version.txt?dl=1Redford
A
12

Apparently there is not.

There's an official HOWTO entry on https://web.archive.org/web/20141101060340/http://developer.nokia.com/community/wiki/Handling_an_HTTP_redirect_with_QNetworkAccessManager

Extraction from link above:

void QNAMRedirect::replyFinished(QNetworkReply* reply) {
    /*
     * Reply is finished!
     * We'll ask for the reply about the Redirection attribute
     * http://doc.trolltech.com/qnetworkrequest.html#Attribute-enum
     */
    QVariant possibleRedirectUrl =
             reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
 
    /* We'll deduct if the redirection is valid in the redirectUrl function */
    _urlRedirectedTo = this->redirectUrl(possibleRedirectUrl.toUrl(),
                                         _urlRedirectedTo);
 
    /* If the URL is not empty, we're being redirected. */
    if(!_urlRedirectedTo.isEmpty()) {
        QString text = QString("QNAMRedirect::replyFinished: Redirected to ")
                              .append(_urlRedirectedTo.toString());
        this->_textContainer->setText(text);
 
        /* We'll do another request to the redirection url. */
        this->_qnam->get(QNetworkRequest(_urlRedirectedTo));
    }
    else {
        /*
         * We weren't redirected anymore
         * so we arrived to the final destination...
         */
        QString text = QString("QNAMRedirect::replyFinished: Arrived to ")
                              .append(reply->url().toString());
        this->_textContainer->setText(text);
        /* ...so this can be cleared. */
        _urlRedirectedTo.clear();
    }
    /* Clean up. */
    reply->deleteLater();
}
 
QUrl QNAMRedirect::redirectUrl(const QUrl& possibleRedirectUrl,
                               const QUrl& oldRedirectUrl) const {
    QUrl redirectUrl;
    /*
     * Check if the URL is empty and
     * that we aren't being fooled into a infinite redirect loop.
     * We could also keep track of how many redirects we have been to
     * and set a limit to it, but we'll leave that to you.
     */
    if(!possibleRedirectUrl.isEmpty() &&
       possibleRedirectUrl != oldRedirectUrl) {
        redirectUrl = possibleRedirectUrl;
    }
    return redirectUrl;
}
Adebayo answered 11/2, 2013 at 9:58 Comment(3)
Thought there might not have been a way but wasn't sure if I was missing something somewhere, thanks for clearing that up @Adebayo :)Kerf
the link to the official HOWTO is broken :(Delighted
@DavidSánchez: Updated the comment to reflect this. Unfortunately the wiki content hasn't been moved before its deletion :(Adebayo

© 2022 - 2024 — McMap. All rights reserved.