mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-05-12 01:19:44 +00:00
QHttpServerResponder: refactor and extend the API
Currently QHttpServerResponder is not flexible enough: - Does not allow to rewrite headers - Does not allow to write headers without storing them internaly first - Does not provide API to make your own HTTP response This patch will help to implement QHttpServerResponse setHeaders/addHeaders Change-Id: If9e21f7f7a58629bfedad0f10cab67d67fce0a89 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
b63b0862c9
commit
055d36692b
src/httpserver
tests/auto
@ -55,8 +55,12 @@ static const std::map<QHttpServerResponder::StatusCode, QByteArray> statusString
|
||||
#undef XX
|
||||
};
|
||||
|
||||
static const QByteArray contentTypeString(QByteArrayLiteral("Content-Type"));
|
||||
static const QByteArray contentLengthString(QByteArrayLiteral("Content-Length"));
|
||||
static const QByteArray contentTypeHeader(QByteArrayLiteral("Content-Type"));
|
||||
static const QByteArray contentLengthHeader(QByteArrayLiteral("Content-Length"));
|
||||
|
||||
static const QByteArray contentTypeEmpty(QByteArrayLiteral("application/x-empty"));
|
||||
static const QByteArray contentTypeJson(QByteArrayLiteral("text/json"));
|
||||
|
||||
|
||||
template <qint64 BUFFERSIZE = 512>
|
||||
struct IOChunkedTransfer
|
||||
@ -165,8 +169,8 @@ QHttpServerResponder::~QHttpServerResponder()
|
||||
{}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status and a
|
||||
MIME type \a mimeType. The I/O device \a data provides the body
|
||||
Answers a request with an HTTP status code \a status and
|
||||
HTTP headers \a headers. The I/O device \a data provides the body
|
||||
of the response. If \a data is sequential, the body of the
|
||||
message is sent in chunks: otherwise, the function assumes all
|
||||
the content is available and sends it all at once but the read
|
||||
@ -175,7 +179,7 @@ QHttpServerResponder::~QHttpServerResponder()
|
||||
\note This function takes the ownership of \a data.
|
||||
*/
|
||||
void QHttpServerResponder::write(QIODevice *data,
|
||||
const QByteArray &mimeType,
|
||||
HeaderList headers,
|
||||
StatusCode status)
|
||||
{
|
||||
Q_D(QHttpServerResponder);
|
||||
@ -202,14 +206,14 @@ void QHttpServerResponder::write(QIODevice *data,
|
||||
return;
|
||||
}
|
||||
|
||||
d->writeStatusLine(status);
|
||||
writeStatusLine(status);
|
||||
|
||||
if (!input->isSequential()) // Non-sequential QIODevice should know its data size
|
||||
d->addHeader(contentLengthString, QByteArray::number(input->size()));
|
||||
writeHeader(contentLengthHeader, QByteArray::number(input->size()));
|
||||
|
||||
d->addHeader(contentTypeString, mimeType);
|
||||
for (auto &&header : headers)
|
||||
writeHeader(header.first, header.second);
|
||||
|
||||
d->writeHeaders();
|
||||
d->socket->write("\r\n");
|
||||
|
||||
if (input->atEnd()) {
|
||||
@ -221,6 +225,73 @@ void QHttpServerResponder::write(QIODevice *data,
|
||||
new IOChunkedTransfer<>(input.take(), d->socket);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status and a
|
||||
MIME type \a mimeType. The I/O device \a data provides the body
|
||||
of the response. If \a data is sequential, the body of the
|
||||
message is sent in chunks: otherwise, the function assumes all
|
||||
the content is available and sends it all at once but the read
|
||||
is done in chunks.
|
||||
|
||||
\note This function takes the ownership of \a data.
|
||||
*/
|
||||
void QHttpServerResponder::write(QIODevice *data,
|
||||
const QByteArray &mimeType,
|
||||
StatusCode status)
|
||||
{
|
||||
write(data, {{ contentTypeHeader, mimeType }}, status);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status, JSON
|
||||
document \a document and HTTP headers \a headers.
|
||||
|
||||
Note: This function sets HTTP Content-Type header as "application/json".
|
||||
*/
|
||||
void QHttpServerResponder::write(const QJsonDocument &document,
|
||||
HeaderList headers,
|
||||
StatusCode status)
|
||||
{
|
||||
const QByteArray &json = document.toJson();
|
||||
writeStatusLine(status);
|
||||
writeHeader(contentTypeHeader, contentTypeJson);
|
||||
writeHeader(contentLengthHeader, QByteArray::number(json.size()));
|
||||
writeHeaders(std::move(headers));
|
||||
writeBody(document.toJson());
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status, and JSON
|
||||
document \a document.
|
||||
|
||||
Note: This function sets HTTP Content-Type header as "application/json".
|
||||
*/
|
||||
void QHttpServerResponder::write(const QJsonDocument &document,
|
||||
StatusCode status)
|
||||
{
|
||||
write(document, {}, status);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status,
|
||||
HTTP Headers \a headers and a body \a data.
|
||||
|
||||
Note: This function sets HTTP Content-Length header.
|
||||
*/
|
||||
void QHttpServerResponder::write(const QByteArray &data,
|
||||
HeaderList headers,
|
||||
StatusCode status)
|
||||
{
|
||||
Q_D(QHttpServerResponder);
|
||||
writeStatusLine(status);
|
||||
|
||||
for (auto &&header : headers)
|
||||
writeHeader(header.first, header.second);
|
||||
|
||||
writeHeader(contentLengthHeader, QByteArray::number(data.size()));
|
||||
writeBody(data);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status, a
|
||||
MIME type \a mimeType and a body \a data.
|
||||
@ -229,29 +300,102 @@ void QHttpServerResponder::write(const QByteArray &data,
|
||||
const QByteArray &mimeType,
|
||||
StatusCode status)
|
||||
{
|
||||
Q_D(QHttpServerResponder);
|
||||
d->writeStatusLine(status);
|
||||
addHeaders(contentTypeString, mimeType,
|
||||
contentLengthString, QByteArray::number(data.size()));
|
||||
d->writeHeaders();
|
||||
d->writeBody(data);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status, and JSON
|
||||
document \a document.
|
||||
*/
|
||||
void QHttpServerResponder::write(const QJsonDocument &document, StatusCode status)
|
||||
{
|
||||
write(document.toJson(), QByteArrayLiteral("text/json"), status);
|
||||
write(data, {{ contentTypeHeader, mimeType }}, status);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status.
|
||||
|
||||
Note: This function sets HTTP Content-Type header as "application/x-empty".
|
||||
*/
|
||||
void QHttpServerResponder::write(StatusCode status)
|
||||
{
|
||||
write(QByteArray(), QByteArrayLiteral("application/x-empty"), status);
|
||||
write(QByteArray(), contentTypeEmpty, status);
|
||||
}
|
||||
|
||||
/*!
|
||||
Answers a request with an HTTP status code \a status and
|
||||
HTTP Headers \a headers.
|
||||
*/
|
||||
void QHttpServerResponder::write(HeaderList headers, StatusCode status)
|
||||
{
|
||||
write(QByteArray(), std::move(headers), status);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes HTTP status line with an HTTP status code \a status
|
||||
and an HTTP version \a version.
|
||||
*/
|
||||
void QHttpServerResponder::writeStatusLine(StatusCode status,
|
||||
const QPair<quint8, quint8> &version)
|
||||
{
|
||||
Q_D(const QHttpServerResponder);
|
||||
Q_ASSERT(d->socket->isOpen());
|
||||
d->socket->write("HTTP/");
|
||||
d->socket->write(QByteArray::number(version.first));
|
||||
d->socket->write(".");
|
||||
d->socket->write(QByteArray::number(version.second));
|
||||
d->socket->write(" ");
|
||||
d->socket->write(QByteArray::number(quint32(status)));
|
||||
d->socket->write(" ");
|
||||
d->socket->write(statusString.at(status));
|
||||
d->socket->write("\r\n");
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes an HTTP header \a header
|
||||
with \a value.
|
||||
*/
|
||||
void QHttpServerResponder::writeHeader(const QByteArray &header,
|
||||
const QByteArray &value)
|
||||
{
|
||||
Q_D(const QHttpServerResponder);
|
||||
Q_ASSERT(d->socket->isOpen());
|
||||
d->socket->write(header);
|
||||
d->socket->write(": ");
|
||||
d->socket->write(value);
|
||||
d->socket->write("\r\n");
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes HTTP headers \a headers.
|
||||
*/
|
||||
void QHttpServerResponder::writeHeaders(HeaderList headers)
|
||||
{
|
||||
for (auto &&header : headers)
|
||||
writeHeader(header.first, header.second);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes HTTP body \a body with size \a size.
|
||||
*/
|
||||
void QHttpServerResponder::writeBody(const char *body, qint64 size)
|
||||
{
|
||||
Q_D(QHttpServerResponder);
|
||||
Q_ASSERT(d->socket->isOpen());
|
||||
|
||||
if (!d->bodyStarted) {
|
||||
d->socket->write("\r\n");
|
||||
d->bodyStarted = true;
|
||||
}
|
||||
|
||||
d->socket->write(body, size);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes HTTP body \a body.
|
||||
*/
|
||||
void QHttpServerResponder::writeBody(const char *body)
|
||||
{
|
||||
writeBody(body, qstrlen(body));
|
||||
}
|
||||
|
||||
/*!
|
||||
This function writes HTTP body \a body.
|
||||
*/
|
||||
void QHttpServerResponder::writeBody(const QByteArray &body)
|
||||
{
|
||||
writeBody(body.constData(), body.size());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -263,47 +407,4 @@ QTcpSocket *QHttpServerResponder::socket() const
|
||||
return d->socket;
|
||||
}
|
||||
|
||||
bool QHttpServerResponder::addHeader(const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
Q_D(QHttpServerResponder);
|
||||
return d->addHeader(key, value);
|
||||
}
|
||||
|
||||
void QHttpServerResponderPrivate::writeStatusLine(StatusCode status,
|
||||
const QPair<quint8, quint8> &version) const
|
||||
{
|
||||
Q_ASSERT(socket->isOpen());
|
||||
socket->write("HTTP/");
|
||||
socket->write(QByteArray::number(version.first));
|
||||
socket->write(".");
|
||||
socket->write(QByteArray::number(version.second));
|
||||
socket->write(" ");
|
||||
socket->write(QByteArray::number(quint32(status)));
|
||||
socket->write(" ");
|
||||
socket->write(statusString.at(status));
|
||||
socket->write("\r\n");
|
||||
}
|
||||
|
||||
void QHttpServerResponderPrivate::writeHeader(const QByteArray &header,
|
||||
const QByteArray &value) const
|
||||
{
|
||||
socket->write(header);
|
||||
socket->write(": ");
|
||||
socket->write(value);
|
||||
socket->write("\r\n");
|
||||
}
|
||||
|
||||
void QHttpServerResponderPrivate::writeHeaders() const
|
||||
{
|
||||
for (const auto &pair : qAsConst(headers()))
|
||||
writeHeader(pair.first, pair.second);
|
||||
}
|
||||
|
||||
void QHttpServerResponderPrivate::writeBody(const QByteArray &body) const
|
||||
{
|
||||
Q_ASSERT(socket->isOpen());
|
||||
socket->write("\r\n");
|
||||
socket->write(body);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -33,12 +33,16 @@
|
||||
#include <QtHttpServer/qthttpserverglobal.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qpair.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qmimetype.h>
|
||||
|
||||
#include <utility>
|
||||
#include <initializer_list>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QTcpSocket;
|
||||
@ -126,39 +130,53 @@ public:
|
||||
NetworkConnectTimeoutError = 599,
|
||||
};
|
||||
|
||||
using HeaderList = std::initializer_list<std::pair<QByteArray, QByteArray>>;
|
||||
|
||||
QHttpServerResponder(QHttpServerResponder &&other);
|
||||
~QHttpServerResponder();
|
||||
|
||||
void write(QIODevice *data, const QByteArray &mimeType, StatusCode status = StatusCode::Ok);
|
||||
void write(QIODevice *data,
|
||||
HeaderList headers,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(QIODevice *data,
|
||||
const QByteArray &mimeType,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(const QJsonDocument &document,
|
||||
HeaderList headers,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(const QJsonDocument &document,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(const QByteArray &data,
|
||||
HeaderList headers,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(const QByteArray &data,
|
||||
const QByteArray &mimeType,
|
||||
StatusCode status = StatusCode::Ok);
|
||||
void write(const QJsonDocument &document, StatusCode status = StatusCode::Ok);
|
||||
|
||||
void write(HeaderList headers, StatusCode status = StatusCode::Ok);
|
||||
void write(StatusCode status = StatusCode::Ok);
|
||||
|
||||
|
||||
void writeStatusLine(StatusCode status = StatusCode::Ok,
|
||||
const QPair<quint8, quint8> &version = qMakePair(1u, 1u));
|
||||
|
||||
void writeHeader(const QByteArray &key, const QByteArray &value);
|
||||
void writeHeaders(HeaderList headers);
|
||||
|
||||
void writeBody(const char *body, qint64 size);
|
||||
void writeBody(const char *body);
|
||||
void writeBody(const QByteArray &body);
|
||||
|
||||
QTcpSocket *socket() const;
|
||||
|
||||
bool addHeader(const QByteArray &key, const QByteArray &value);
|
||||
|
||||
template <typename... Args>
|
||||
inline void addHeaders(const QPair<QByteArray, QByteArray> &first, Args &&... others)
|
||||
{
|
||||
addHeader(first.first, first.second);
|
||||
addHeaders(std::forward<Args>(others)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void addHeaders(const QByteArray &key, const QByteArray &value, Args &&... others)
|
||||
{
|
||||
addHeader(key, value);
|
||||
addHeaders(std::forward<Args>(others)...);
|
||||
}
|
||||
|
||||
private:
|
||||
QHttpServerResponder(const QHttpServerRequest &request, QTcpSocket *socket);
|
||||
|
||||
inline void addHeaders() {}
|
||||
|
||||
QScopedPointer<QHttpServerResponderPrivate> d_ptr;
|
||||
};
|
||||
|
||||
|
@ -55,33 +55,9 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
class QHttpServerResponderPrivate
|
||||
{
|
||||
using StatusCode = QHttpServerResponder::StatusCode;
|
||||
|
||||
public:
|
||||
QHttpServerResponderPrivate(const QHttpServerRequest &request, QTcpSocket *const socket) :
|
||||
request(request),
|
||||
socket(socket)
|
||||
{
|
||||
const auto server = QStringLiteral("%1/%2(%3)").arg(
|
||||
QCoreApplication::instance()->applicationName(),
|
||||
QCoreApplication::instance()->applicationVersion(),
|
||||
QSysInfo::prettyProductName());
|
||||
addHeader(QByteArrayLiteral("Server"), server.toUtf8());
|
||||
}
|
||||
|
||||
inline bool addHeader(const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
const auto hash = qHash(key.toLower());
|
||||
if (m_headers.contains(hash))
|
||||
return false;
|
||||
m_headers.insert(hash, qMakePair(key, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeStatusLine(StatusCode status = StatusCode::Ok,
|
||||
const QPair<quint8, quint8> &version = qMakePair(1u, 1u)) const;
|
||||
void writeHeaders() const;
|
||||
void writeBody(const QByteArray &body) const;
|
||||
QHttpServerResponderPrivate(const QHttpServerRequest &request, QTcpSocket *const socket)
|
||||
: request(request), socket(socket) {}
|
||||
|
||||
const QHttpServerRequest &request;
|
||||
#if defined(QT_DEBUG)
|
||||
@ -89,14 +65,7 @@ public:
|
||||
#else
|
||||
QTcpSocket *const socket;
|
||||
#endif
|
||||
|
||||
QMap<uint, QPair<QByteArray, QByteArray>> m_headers;
|
||||
|
||||
private:
|
||||
void writeHeader(const QByteArray &header, const QByteArray &value) const;
|
||||
|
||||
public:
|
||||
const decltype(m_headers) &headers() const { return m_headers; }
|
||||
bool bodyStarted{false};
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -215,6 +215,24 @@ void tst_QHttpServer::initTestCase()
|
||||
};
|
||||
});
|
||||
|
||||
httpserver.route("/chunked/", [] (QHttpServerResponder &&responder) {
|
||||
responder.writeStatusLine(QHttpServerResponder::StatusCode::Ok);
|
||||
responder.writeHeaders({
|
||||
{"Content-Type", "text/plain"},
|
||||
{"Transfer-Encoding", "chunked"} });
|
||||
|
||||
auto writeChunk = [&responder] (const char *message) {
|
||||
responder.writeBody(QByteArray::number(qstrlen(message), 16));
|
||||
responder.writeBody("\r\n");
|
||||
responder.writeBody(message);
|
||||
responder.writeBody("\r\n");
|
||||
};
|
||||
|
||||
writeChunk("part 1 of the message, ");
|
||||
writeChunk("part 2 of the message");
|
||||
writeChunk("");
|
||||
});
|
||||
|
||||
urlBase = QStringLiteral("http://localhost:%1%2").arg(httpserver.listen());
|
||||
}
|
||||
|
||||
@ -391,6 +409,12 @@ void tst_QHttpServer::routeGet_data()
|
||||
<< 200
|
||||
<< "application/json"
|
||||
<< "[1,\"2\",{\"name\":\"test\"}]";
|
||||
|
||||
QTest::addRow("chunked")
|
||||
<< "/chunked/"
|
||||
<< 200
|
||||
<< "text/plain"
|
||||
<< "part 1 of the message, part 2 of the message";
|
||||
}
|
||||
|
||||
void tst_QHttpServer::routeGet()
|
||||
|
@ -41,6 +41,9 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static const QByteArray headerServerString(QByteArrayLiteral("Server"));
|
||||
static const QByteArray headerServerValue(QByteArrayLiteral("Test server"));
|
||||
|
||||
class tst_QHttpServerResponder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -56,9 +59,13 @@ private slots:
|
||||
void defaultStatusCodeJson();
|
||||
void writeStatusCode_data();
|
||||
void writeStatusCode();
|
||||
void writeStatusCodeExtraHeader();
|
||||
void writeJson();
|
||||
void writeJsonExtraHeader();
|
||||
void writeFile_data();
|
||||
void writeFile();
|
||||
void writeFileExtraHeader();
|
||||
void writeByteArrayExtraHeader();
|
||||
};
|
||||
|
||||
#define qWaitForFinished(REPLY) QVERIFY(QSignalSpy(REPLY, &QNetworkReply::finished).wait())
|
||||
@ -131,10 +138,18 @@ void tst_QHttpServerResponder::writeStatusCode()
|
||||
QCOMPARE(reply->error(), networkError);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader),
|
||||
QByteArrayLiteral("application/x-empty"));
|
||||
QCOMPARE(reply->header(QNetworkRequest::ServerHeader), QStringLiteral("%1/%2(%3)")
|
||||
.arg(QCoreApplication::instance()->applicationName())
|
||||
.arg(QCoreApplication::instance()->applicationVersion())
|
||||
.arg(QSysInfo::prettyProductName()).toUtf8());
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeStatusCodeExtraHeader()
|
||||
{
|
||||
HttpServer server([=](QHttpServerResponder responder) {
|
||||
responder.write({{ headerServerString, headerServerValue }});
|
||||
});
|
||||
auto reply = networkAccessManager->get(QNetworkRequest(server.url));
|
||||
qWaitForFinished(reply);
|
||||
QCOMPARE(reply->bytesAvailable(), 0);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ServerHeader), headerServerValue);
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeJson()
|
||||
@ -148,6 +163,20 @@ void tst_QHttpServerResponder::writeJson()
|
||||
QCOMPARE(QJsonDocument::fromJson(reply->readAll()), json);
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeJsonExtraHeader()
|
||||
{
|
||||
const auto json = QJsonDocument::fromJson(QByteArrayLiteral(R"JSON({ "key" : "value" })JSON"));
|
||||
HttpServer server([json](QHttpServerResponder responder) {
|
||||
responder.write(json, {{ headerServerString, headerServerValue }});
|
||||
});
|
||||
auto reply = networkAccessManager->get(QNetworkRequest(server.url));
|
||||
qWaitForFinished(reply);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), QByteArrayLiteral("text/json"));
|
||||
QCOMPARE(reply->header(QNetworkRequest::ServerHeader), headerServerValue);
|
||||
QCOMPARE(QJsonDocument::fromJson(reply->readAll()), json);
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeFile_data()
|
||||
{
|
||||
QTest::addColumn<QIODevice *>("iodevice");
|
||||
@ -196,6 +225,51 @@ void tst_QHttpServerResponder::writeFile()
|
||||
QCOMPARE(spyDestroyIoDevice.count(), 1);
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeFileExtraHeader()
|
||||
{
|
||||
auto file = new QFile(QFINDTESTDATA("index.html"), this);
|
||||
QSignalSpy spyDestroyIoDevice(file, &QObject::destroyed);
|
||||
const QByteArray contentType("text/html");
|
||||
|
||||
HttpServer server([=](QHttpServerResponder responder) {
|
||||
responder.write(
|
||||
file,
|
||||
{
|
||||
{ "Content-Type", contentType },
|
||||
{ headerServerString, headerServerValue }
|
||||
});
|
||||
});
|
||||
auto reply = networkAccessManager->get(QNetworkRequest(server.url));
|
||||
QTRY_VERIFY(reply->isFinished());
|
||||
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), contentType);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ServerHeader), headerServerValue);
|
||||
QCOMPARE(reply->readAll().trimmed(), "<html></html>");
|
||||
|
||||
QCOMPARE(spyDestroyIoDevice.count(), 1);
|
||||
}
|
||||
|
||||
void tst_QHttpServerResponder::writeByteArrayExtraHeader()
|
||||
{
|
||||
const QByteArray data("test data");
|
||||
const QByteArray contentType("text/plain");
|
||||
|
||||
HttpServer server([=](QHttpServerResponder responder) {
|
||||
responder.write(
|
||||
data,
|
||||
{
|
||||
{ "Content-Type", contentType },
|
||||
{ headerServerString, headerServerValue }
|
||||
});
|
||||
});
|
||||
auto reply = networkAccessManager->get(QNetworkRequest(server.url));
|
||||
QTRY_VERIFY(reply->isFinished());
|
||||
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), contentType);
|
||||
QCOMPARE(reply->header(QNetworkRequest::ServerHeader), headerServerValue);
|
||||
QCOMPARE(reply->readAll(), data);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QTEST_MAIN(tst_QHttpServerResponder)
|
||||
|
Loading…
x
Reference in New Issue
Block a user