简体   繁体   中英

QNetworkAccessManager doesn't handle HTTP Status Code 308

I'm testing my code for compatibility with HTTP 3xx status codes (redirects).

I'm interested in codes 301, 302, 303, 307 and 308.

All of those work fine with my code, except 308.

My client testcase is Qt/C++ based, and my testing server is python-based. I'll post the code of both.

client.cpp :

#include <QGuiApplication>
#include <QObject>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);

    QNetworkAccessManager webCtrl;
    QObject::connect(&webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* reply) {
        if(reply->error() != QNetworkReply::NoError) {
            qDebug() << "got error";
        }
        QByteArray data = reply->readAll();
        qDebug() << "got" << data.length() << "bytes";
    });

    QNetworkRequest request(QUrl("http://localhost:8080/not_working"));
    request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
    webCtrl.get(request);

    return app.exec();
}

test_server.py :

#!/usr/bin/env python

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os

class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/working':
            self.send_response(200)
            self.send_header('Content-type','text-html')
            self.end_headers()

            self.wfile.write("hey")
        elif self.path == '/not_working':
            self.send_response(308)
            self.send_header('Location','/working')
            self.end_headers()

server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, MyHTTPRequestHandler)
httpd.serve_forever()

I run the server, then while it's running, I run the client and I get got 0 bytes in the console. If I change the response from 308 to, say, 301, it works fine (prints got 3 bytes ).

Any idea why?

Note: The redirect works fine in Chrome, so my server code is likely correct.

Note: It seems like it's documented as unsupported. From the docs :

This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was set in the request and the server responded with a 3xx status (specifically 301, 302, 303, 305 or 307 status code) with a valid url in the location header, indicating a HTTP redirect.

(emphasis mine)

I'd still like to know why , though.

For anyone who has the same problem, here's my FileDownloader class with support for 308.

filedownloader.cpp :

#include "filedownloader.h"

FileDownloader::FileDownloader(QUrl imageUrl, QObject *parent) :
    QObject(parent)
{
    m_imageUrl = imageUrl;

    connect(
        &m_webCtrl, SIGNAL (finished(QNetworkReply*)),
        this, SLOT (onDownloaded_internal(QNetworkReply*))
        );

    QNetworkRequest request(imageUrl);
    request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
    m_webCtrl.get(request);
}

FileDownloader::~FileDownloader() {
}

void FileDownloader::onDownloaded_internal(QNetworkReply* reply) {
    if(reply->error() != QNetworkReply::NoError) {
        qDebug() << "error " << reply->error();
        emit error();
        return;
    }
    if(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 308) {
        handleRedirect308(reply);
        return;
    }
    QByteArray data = reply->readAll();
    reply->deleteLater();
    emit downloaded(data);
    deleteLater();
}

void FileDownloader::handleRedirect308(QNetworkReply *reply) {
    QByteArray header = reply->rawHeader("location");
    QUrl url(QString::fromUtf8(header));
    url = m_imageUrl.resolved(url);
    QNetworkRequest request(url);
    qDebug() << "308 to " << url;
    request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
    m_webCtrl.get(request);
}

filedownloader.h:

#ifndef FILEDOWNLOADER_H
#define FILEDOWNLOADER_H

#include <QObject>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

class FileDownloader : public QObject {
    Q_OBJECT
public:
    explicit FileDownloader(QUrl imageUrl, QObject *parent = 0);
    virtual ~FileDownloader();

signals:
    void downloaded(QByteArray const& data);
    void error();

private slots:
    void onDownloaded_internal(QNetworkReply* reply);

private:
    void handleRedirect308(QNetworkReply* reply);

    QNetworkAccessManager m_webCtrl;
    QUrl m_imageUrl;
};

#endif // FILEDOWNLOADER_H

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM