mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-04-26 10:24:31 +00:00
Add QHttpServer::afterRequest
This function allows to register a function to be run after each request. Task-number: QTBUG-77090 Change-Id: I40dd4c1e9a447fbe034149ffc1923c7c814cf0e9 Reviewed-by: Mikhail Svetkin <mikhail.svetkin@gmail.com>
This commit is contained in:
parent
f28694ea2c
commit
e0fa374411
@ -1,3 +1,4 @@
|
||||
# Generated from httpserver.pro.
|
||||
|
||||
add_subdirectory(afterrequest)
|
||||
add_subdirectory(simple)
|
||||
|
27
examples/httpserver/afterrequest/CMakeLists.txt
Normal file
27
examples/httpserver/afterrequest/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# Generated from afterrequest.pro.
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(afterrequest LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "examples/httpserver/afterrequest")
|
||||
|
||||
find_package(Qt6 COMPONENTS HttpServer)
|
||||
|
||||
add_executable(afterrequest
|
||||
main.cpp
|
||||
)
|
||||
target_link_libraries(afterrequest PUBLIC
|
||||
Qt::HttpServer
|
||||
)
|
||||
|
||||
install(TARGETS afterrequest
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
13
examples/httpserver/afterrequest/afterrequest.pro
Normal file
13
examples/httpserver/afterrequest/afterrequest.pro
Normal file
@ -0,0 +1,13 @@
|
||||
requires(qtHaveModule(httpserver))
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
QT = httpserver
|
||||
|
||||
SOURCES += \
|
||||
main.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/httpserver/afterrequest
|
||||
INSTALLS += target
|
||||
|
||||
CONFIG += cmdline
|
80
examples/httpserver/afterrequest/main.cpp
Normal file
80
examples/httpserver/afterrequest/main.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtHttpServer>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QHttpServer httpServer;
|
||||
httpServer.route("/", []() {
|
||||
return "Hello world";
|
||||
});
|
||||
|
||||
httpServer.afterRequest([](QHttpServerResponse &&resp) {
|
||||
resp.setHeader("Server", "Super server!");
|
||||
return std::move(resp);
|
||||
});
|
||||
|
||||
const auto port = httpServer.listen(QHostAddress::Any);
|
||||
if (!port) {
|
||||
qDebug() << QCoreApplication::translate(
|
||||
"QHttpServerExample", "Server failed to listen on a port.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
qDebug() << QCoreApplication::translate(
|
||||
"QHttpServerExample", "Running on http://127.0.0.1:%1/ (Press CTRL+C to quit)").arg(port);
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = \
|
||||
afterrequest \
|
||||
simple
|
||||
|
||||
|
@ -16,6 +16,8 @@ qt_add_module(HttpServer
|
||||
qhttpserverrouter.cpp qhttpserverrouter.h qhttpserverrouter_p.h
|
||||
qhttpserverrouterrule.cpp qhttpserverrouterrule.h qhttpserverrouterrule_p.h
|
||||
qhttpserverrouterviewtraits.h
|
||||
qhttpserverviewtraits.h
|
||||
qhttpserverviewtraits_impl.h
|
||||
qthttpserverglobal.h
|
||||
INCLUDE_DIRECTORIES
|
||||
.
|
||||
@ -45,10 +47,3 @@ qt_extend_target(HttpServer CONDITION QT_FEATURE_ssl
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::SslServer
|
||||
)
|
||||
|
||||
qt_extend_target(HttpServer CONDITION TARGET Qt::Concurrent
|
||||
SOURCES
|
||||
qhttpserverfutureresponse.cpp qhttpserverfutureresponse.h
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Concurrent
|
||||
)
|
||||
|
@ -23,7 +23,9 @@ HEADERS += \
|
||||
qhttpserverrouter_p.h \
|
||||
qhttpserverrouterrule.h \
|
||||
qhttpserverrouterrule_p.h \
|
||||
qhttpserverrouterviewtraits.h
|
||||
qhttpserverrouterviewtraits.h \
|
||||
qhttpserverviewtraits.h \
|
||||
qhttpserverviewtraits_impl.h
|
||||
|
||||
SOURCES += \
|
||||
qabstracthttpserver.cpp \
|
||||
|
@ -66,8 +66,7 @@ QHttpServer::QHttpServer(QObject *parent)
|
||||
connect(this, &QAbstractHttpServer::missingHandler, this,
|
||||
[=] (const QHttpServerRequest &request, QTcpSocket *socket) {
|
||||
qCDebug(lcHS) << tr("missing handler:") << request.url().path();
|
||||
sendResponse(
|
||||
QHttpServerResponse(QHttpServerResponder::StatusCode::NotFound), request, socket);
|
||||
sendResponse(QHttpServerResponder::StatusCode::NotFound, request, socket);
|
||||
});
|
||||
}
|
||||
|
||||
@ -103,6 +102,40 @@ QHttpServer::QHttpServer(QObject *parent)
|
||||
\sa QHttpServerRouter::addRule
|
||||
*/
|
||||
|
||||
/*! \fn template<typename ViewHandler> void afterRequest(ViewHandler &&viewHandler)
|
||||
Register a function to be run after each request.
|
||||
|
||||
\c ViewHandler can only be a lambda. The lambda definition can take two
|
||||
arguments: \c {QHttpServerResponse &&} and \c {const QHttpServerRequest&} (optional).
|
||||
|
||||
Examples:
|
||||
|
||||
\code
|
||||
|
||||
QHttpServer server;
|
||||
|
||||
// Valid:
|
||||
server.afterRequest([] (QHttpServerResponse &&resp, const QHttpServerRequest &request) {
|
||||
return std::move(resp);
|
||||
}
|
||||
server.afterRequest([] (const QHttpServerRequest &request, QHttpServerResponse &&resp) {
|
||||
return std::move(resp);
|
||||
}
|
||||
server.afterRequest([] (QHttpServerResponse &&resp) { return std::move(resp); }
|
||||
|
||||
// Invalid (compile time error):
|
||||
// resp must be passed by universal reference
|
||||
server.afterRequest([] (QHttpServerResponse &resp, const QHttpServerRequest &request) {
|
||||
return std::move(resp);
|
||||
}
|
||||
// request must be passed by const reference
|
||||
server.afterRequest([] (QHttpServerResponse &&resp, QHttpServerRequest &request) {
|
||||
return std::move(resp);
|
||||
}
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*!
|
||||
Destroys a QHttpServer.
|
||||
*/
|
||||
@ -119,13 +152,22 @@ QHttpServerRouter *QHttpServer::router()
|
||||
return &d->router;
|
||||
}
|
||||
|
||||
void QHttpServer::afterRequestImpl(AfterRequestHandler &&afterRequestHandler)
|
||||
{
|
||||
Q_D(QHttpServer);
|
||||
d->afterRequestHandlers.push_back(std::move(afterRequestHandler));
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QHttpServer::sendResponse(const QHttpServerResponse &response,
|
||||
void QHttpServer::sendResponse(QHttpServerResponse &&response,
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket)
|
||||
{
|
||||
Q_D(QHttpServer);
|
||||
for (auto afterRequestHandler : d->afterRequestHandlers)
|
||||
response = std::move(afterRequestHandler(std::move(response), request));
|
||||
response.write(makeResponder(request, socket));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@ -35,6 +36,7 @@
|
||||
#include <QtHttpServer/qhttpserverrouterrule.h>
|
||||
#include <QtHttpServer/qhttpserverresponse.h>
|
||||
#include <QtHttpServer/qhttpserverrouterviewtraits.h>
|
||||
#include <QtHttpServer/qhttpserverviewtraits.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
@ -75,6 +77,57 @@ public:
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ViewHandler>
|
||||
void afterRequest(ViewHandler &&viewHandler)
|
||||
{
|
||||
using ViewTraits = QHttpServerAfterRequestViewTraits<ViewHandler>;
|
||||
static_assert(ViewTraits::Arguments::StaticAssert,
|
||||
"ViewHandler arguments are in the wrong order or not supported");
|
||||
afterRequestHelper<ViewTraits, ViewHandler>(std::move(viewHandler));
|
||||
}
|
||||
|
||||
using AfterRequestHandler =
|
||||
std::function<QHttpServerResponse(QHttpServerResponse &&response,
|
||||
const QHttpServerRequest &request)>;
|
||||
private:
|
||||
template<typename ViewTraits, typename ViewHandler>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsRequest::Value &&
|
||||
ViewTraits::Arguments::Count == 2, void>::type
|
||||
afterRequestHelper(ViewHandler &&viewHandler) {
|
||||
auto handler = [viewHandler](QHttpServerResponse &&resp,
|
||||
const QHttpServerRequest &request) {
|
||||
return std::move(viewHandler(std::move(resp), request));
|
||||
};
|
||||
|
||||
afterRequestImpl(std::move(handler));
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename ViewHandler>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsResponse::Value &&
|
||||
ViewTraits::Arguments::Count == 1, void>::type
|
||||
afterRequestHelper(ViewHandler &&viewHandler) {
|
||||
auto handler = [viewHandler](QHttpServerResponse &&resp,
|
||||
const QHttpServerRequest &) {
|
||||
return std::move(viewHandler(std::move(resp)));
|
||||
};
|
||||
|
||||
afterRequestImpl(std::move(handler));
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename ViewHandler>
|
||||
typename std::enable_if<ViewTraits::Arguments::Last::IsResponse::Value &&
|
||||
ViewTraits::Arguments::Count == 2, void>::type
|
||||
afterRequestHelper(ViewHandler &&viewHandler) {
|
||||
auto handler = [viewHandler](QHttpServerResponse &&resp,
|
||||
const QHttpServerRequest &request) {
|
||||
return std::move(viewHandler(request, std::move(resp)));
|
||||
};
|
||||
|
||||
afterRequestImpl(std::move(handler));
|
||||
}
|
||||
|
||||
void afterRequestImpl(AfterRequestHandler &&afterRequestHandler);
|
||||
|
||||
private:
|
||||
template<typename Rule, typename ViewHandler, typename ViewTraits, int ... I, typename ... Args>
|
||||
bool routeHelper(QtPrivate::IndexesList<I...>, Args &&... args)
|
||||
@ -107,8 +160,8 @@ private:
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket)
|
||||
{
|
||||
const QHttpServerResponse response(boundViewHandler());
|
||||
sendResponse(response, request, socket);
|
||||
QHttpServerResponse response(boundViewHandler());
|
||||
sendResponse(std::move(response), request, socket);
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename T>
|
||||
@ -124,8 +177,8 @@ private:
|
||||
ViewTraits::Arguments::PlaceholdersCount == 1, void>::type
|
||||
responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket)
|
||||
{
|
||||
const QHttpServerResponse response(boundViewHandler(request));
|
||||
sendResponse(response, request, socket);
|
||||
QHttpServerResponse response(boundViewHandler(request));
|
||||
sendResponse(std::move(response), request, socket);
|
||||
}
|
||||
|
||||
template<typename ViewTraits, typename T>
|
||||
@ -150,7 +203,7 @@ private:
|
||||
|
||||
bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) override final;
|
||||
|
||||
void sendResponse(const QHttpServerResponse &response,
|
||||
void sendResponse(QHttpServerResponse &&response,
|
||||
const QHttpServerRequest &request,
|
||||
QTcpSocket *socket);
|
||||
};
|
||||
|
@ -49,6 +49,8 @@
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QHttpServerPrivate: public QAbstractHttpServerPrivate
|
||||
@ -59,6 +61,7 @@ public:
|
||||
QHttpServerPrivate() = default;
|
||||
|
||||
QHttpServerRouter router;
|
||||
std::list<QHttpServer::AfterRequestHandler> afterRequestHandlers;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -40,11 +40,20 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other)
|
||||
QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept
|
||||
: d_ptr(other.d_ptr.take())
|
||||
{
|
||||
}
|
||||
|
||||
QHttpServerResponse& QHttpServerResponse::operator=(QHttpServerResponse &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
qSwap(d_ptr, other.d_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QHttpServerResponse::QHttpServerResponse(
|
||||
const QHttpServerResponse::StatusCode statusCode)
|
||||
: QHttpServerResponse(QHttpServerLiterals::contentTypeXEmpty(),
|
||||
|
@ -50,8 +50,8 @@ public:
|
||||
QHttpServerResponse(const QHttpServerResponse &other) = delete;
|
||||
QHttpServerResponse& operator=(const QHttpServerResponse &other) = delete;
|
||||
|
||||
QHttpServerResponse(QHttpServerResponse &&other);
|
||||
QHttpServerResponse& operator=(QHttpServerResponse &&other) = delete;
|
||||
QHttpServerResponse(QHttpServerResponse &&other) noexcept;
|
||||
QHttpServerResponse& operator=(QHttpServerResponse &&other) noexcept;
|
||||
|
||||
QHttpServerResponse(const StatusCode statusCode);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@ -30,14 +31,7 @@
|
||||
#ifndef QHTTPSERVERROUTERVIEWTRAITS_H
|
||||
#define QHTTPSERVERROUTERVIEWTRAITS_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
#include <QtCore/qobjectdefs.h>
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <QtHttpServer/qhttpserverviewtraits_impl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -46,220 +40,53 @@ class QHttpServerResponder;
|
||||
|
||||
namespace QtPrivate {
|
||||
|
||||
template<typename T>
|
||||
struct RemoveCVRef
|
||||
{
|
||||
using Type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
};
|
||||
|
||||
|
||||
template<bool classMember, typename ReturnT, typename ... Args>
|
||||
struct FunctionTraitsHelper
|
||||
{
|
||||
static constexpr const int ArgumentCount = sizeof ... (Args);
|
||||
static constexpr const int ArgumentIndexMax = ArgumentCount - 1;
|
||||
static constexpr const bool IsClassMember = classMember;
|
||||
using ReturnType = ReturnT;
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using Type = typename std::tuple_element<I, std::tuple<Args...>>::type;
|
||||
|
||||
using CleanType = typename QtPrivate::RemoveCVRef<Type>::Type;
|
||||
|
||||
static constexpr bool Defined = QMetaTypeId2<CleanType>::Defined;
|
||||
};
|
||||
};
|
||||
|
||||
template<bool classMember, typename ReturnT>
|
||||
struct FunctionTraitsHelper<classMember, ReturnT>
|
||||
{
|
||||
static constexpr const int ArgumentCount = 0;
|
||||
static constexpr const int ArgumentIndexMax = -1;
|
||||
static constexpr const bool IsClassMember = classMember;
|
||||
using ReturnType = ReturnT;
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using Type = std::false_type;
|
||||
using CleanType = Type;
|
||||
static constexpr bool Defined = QMetaTypeId2<CleanType>::Defined;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct FunctionTraits;
|
||||
|
||||
template<typename T>
|
||||
struct FunctionTraits : public FunctionTraits<decltype(&T::operator())>{};
|
||||
|
||||
template<typename ReturnT, typename ... Args>
|
||||
struct FunctionTraits<ReturnT (*)(Args...)>
|
||||
: public FunctionTraitsHelper<false, ReturnT, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template<class ReturnT, class ClassT, class ...Args>
|
||||
struct FunctionTraits<ReturnT (ClassT::*)(Args...) const>
|
||||
: public FunctionTraitsHelper<true, ReturnT, Args...>
|
||||
{
|
||||
using classType = ClassT;
|
||||
};
|
||||
|
||||
template<typename ViewHandler, bool DisableStaticAssert>
|
||||
struct ViewTraitsHelper {
|
||||
using FunctionTraits = typename QtPrivate::FunctionTraits<ViewHandler>;
|
||||
using ArgumentIndexes = typename QtPrivate::Indexes<FunctionTraits::ArgumentCount>::Value;
|
||||
struct RouterViewTraitsHelper : ViewTraits<ViewHandler, DisableStaticAssert> {
|
||||
using VTraits = ViewTraits<ViewHandler, DisableStaticAssert>;
|
||||
using FunctionTraits = typename VTraits::FTraits;
|
||||
|
||||
struct StaticMath {
|
||||
template <template<typename> class Predicate, bool defaultValue>
|
||||
struct Loop {
|
||||
static constexpr bool eval() noexcept {
|
||||
return defaultValue;
|
||||
}
|
||||
template<int I>
|
||||
struct ArgumentChecker : FunctionTraits::template Arg<I> {
|
||||
using IsRequest = typename VTraits::template Special<I, const QHttpServerRequest &>;
|
||||
static_assert(IsRequest::AssertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerRequest can only be passed as a const reference");
|
||||
|
||||
template<typename T, typename ... N>
|
||||
static constexpr T eval(const T it, N ...n) noexcept {
|
||||
return Predicate<T>::eval(it, eval(n...));
|
||||
}
|
||||
using IsResponder = typename VTraits::template Special<I, QHttpServerResponder &&>;
|
||||
static_assert(IsResponder::AssertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerResponder can only be passed as a universal reference");
|
||||
|
||||
using IsSpecial = CheckAny<IsRequest, IsResponder>;
|
||||
|
||||
struct IsSimple {
|
||||
static constexpr bool Value = !IsSpecial::Value &&
|
||||
I < FunctionTraits::ArgumentCount &&
|
||||
FunctionTraits::ArgumentIndexMax != -1;
|
||||
static constexpr bool Valid = FunctionTraits::template Arg<I>::Defined;
|
||||
|
||||
static constexpr bool StaticAssert =
|
||||
DisableStaticAssert || !Value || Valid;
|
||||
|
||||
|
||||
static_assert(StaticAssert,
|
||||
"ViewHandler arguments error: "
|
||||
"Type is not registered, please use the Q_DECLARE_METATYPE macro "
|
||||
"to make it known to Qt's meta-object system");
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SumPredicate {
|
||||
static constexpr T eval(const T rs, const T ls) noexcept
|
||||
{
|
||||
return rs + ls;
|
||||
}
|
||||
};
|
||||
using CheckOk = CheckAny<IsSimple, IsSpecial>;
|
||||
|
||||
template<typename T>
|
||||
struct AndPredicate {
|
||||
static constexpr T eval(const T rs, const T ls) noexcept
|
||||
{
|
||||
return rs && ls;
|
||||
}
|
||||
};
|
||||
|
||||
using Sum = Loop<SumPredicate, false>;
|
||||
using And = Loop<AndPredicate, true>;
|
||||
using Or = Sum;
|
||||
static constexpr bool Valid = CheckOk::Valid;
|
||||
static constexpr bool StaticAssert = CheckOk::StaticAssert;
|
||||
};
|
||||
|
||||
|
||||
struct Arguments {
|
||||
template<int I>
|
||||
struct StaticCheck {
|
||||
using Arg = typename FunctionTraits::template Arg<I>;
|
||||
using CleanType = typename Arg::CleanType;
|
||||
|
||||
template<typename T, bool Clean = false>
|
||||
static constexpr bool isType() noexcept
|
||||
{
|
||||
using SelectedType =
|
||||
typename std::conditional<
|
||||
Clean,
|
||||
CleanType,
|
||||
typename Arg::Type
|
||||
>::type;
|
||||
return std::is_same<SelectedType, T>::value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct SpecialHelper {
|
||||
using CleanTypeT = typename QtPrivate::RemoveCVRef<T>::Type;
|
||||
|
||||
static constexpr bool TypeMatched = isType<CleanTypeT, true>();
|
||||
static constexpr bool TypeCVRefMatched = isType<T>();
|
||||
|
||||
static constexpr bool ValidPosition =
|
||||
(I == FunctionTraits::ArgumentIndexMax ||
|
||||
I == FunctionTraits::ArgumentIndexMax - 1);
|
||||
static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition;
|
||||
|
||||
static constexpr bool assertCondition =
|
||||
DisableStaticAssert || !TypeMatched || TypeCVRefMatched;
|
||||
|
||||
static constexpr bool assertConditionOrder =
|
||||
DisableStaticAssert || !TypeMatched || ValidPosition;
|
||||
|
||||
static constexpr bool staticAssert() noexcept
|
||||
{
|
||||
static_assert(assertConditionOrder,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerRequest or QHttpServerResponder"
|
||||
" can only be the last argument");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct CheckAny {
|
||||
static constexpr bool Value = StaticMath::Or::eval(T::Value...);
|
||||
static constexpr bool Valid = StaticMath::Or::eval(T::Valid...);
|
||||
static constexpr bool staticAssert() noexcept
|
||||
{
|
||||
return StaticMath::Or::eval(T::staticAssert()...);
|
||||
}
|
||||
};
|
||||
|
||||
struct IsRequest {
|
||||
using Helper = SpecialHelper<const QHttpServerRequest &>;
|
||||
static constexpr bool Value = Helper::TypeMatched;
|
||||
static constexpr bool Valid = Helper::ValidAll;
|
||||
|
||||
static constexpr bool staticAssert() noexcept
|
||||
{
|
||||
static_assert(Helper::assertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerRequest can only be passed as a const reference");
|
||||
return Helper::staticAssert();
|
||||
}
|
||||
};
|
||||
|
||||
struct IsResponder {
|
||||
using Helper = SpecialHelper<QHttpServerResponder &&>;
|
||||
static constexpr bool Value = Helper::TypeMatched;
|
||||
static constexpr bool Valid = Helper::ValidAll;
|
||||
|
||||
static constexpr bool staticAssert() noexcept
|
||||
{
|
||||
static_assert(Helper::assertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerResponder can only be passed as a universal reference");
|
||||
return Helper::staticAssert();
|
||||
}
|
||||
};
|
||||
|
||||
using IsSpecial = CheckAny<IsRequest, IsResponder>;
|
||||
|
||||
struct IsSimple {
|
||||
static constexpr bool Value = !IsSpecial::Value &&
|
||||
I < FunctionTraits::ArgumentCount &&
|
||||
FunctionTraits::ArgumentIndexMax != -1;
|
||||
static constexpr bool Valid = Arg::Defined;
|
||||
|
||||
static constexpr bool assertCondition =
|
||||
DisableStaticAssert || !Value || Valid;
|
||||
|
||||
static constexpr bool staticAssert() noexcept
|
||||
{
|
||||
static_assert(assertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"Type is not registered, please use the Q_DECLARE_METATYPE macro "
|
||||
"to make it known to Qt's meta-object system");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using CheckOk = CheckAny<IsSimple, IsSpecial>;
|
||||
|
||||
static constexpr bool Valid = CheckOk::Valid;
|
||||
static constexpr bool StaticAssert = CheckOk::staticAssert();
|
||||
};
|
||||
|
||||
template<int ... I>
|
||||
struct ArgumentsReturn {
|
||||
template<int Idx>
|
||||
using Arg = StaticCheck<Idx>;
|
||||
using Arg = ArgumentChecker<Idx>;
|
||||
|
||||
template<int Idx>
|
||||
static constexpr int metaTypeId() noexcept
|
||||
@ -279,9 +106,9 @@ struct ViewTraitsHelper {
|
||||
static_cast<std::size_t>(FunctionTraits::template Arg<I>::Defined)...);
|
||||
static constexpr std::size_t PlaceholdersCount = Count - CapturableCount;
|
||||
|
||||
static constexpr bool Valid = StaticMath::And::eval(StaticCheck<I>::Valid...);
|
||||
static constexpr bool Valid = StaticMath::And::eval(Arg<I>::Valid...);
|
||||
static constexpr bool StaticAssert =
|
||||
StaticMath::And::eval(StaticCheck<I>::StaticAssert...);
|
||||
StaticMath::And::eval(Arg<I>::StaticAssert...);
|
||||
|
||||
using Indexes = typename QtPrivate::IndexesList<I...>;
|
||||
|
||||
@ -317,18 +144,20 @@ struct ViewTraitsHelper {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace QtPrivate
|
||||
|
||||
template <typename ViewHandler, bool DisableStaticAssert = false>
|
||||
struct QHttpServerRouterViewTraits
|
||||
{
|
||||
using Helpers = typename QtPrivate::ViewTraitsHelper<ViewHandler, DisableStaticAssert>;
|
||||
using Helpers = typename QtPrivate::RouterViewTraitsHelper<ViewHandler, DisableStaticAssert>;
|
||||
using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{}));
|
||||
using BindableType = decltype(
|
||||
Helpers::template BindType<Arguments::CapturableCount>::eval(
|
||||
typename Arguments::PlaceholdersIndexes{}));
|
||||
};
|
||||
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERROUTERVIEWTRAITS_H
|
||||
|
109
src/httpserver/qhttpserverviewtraits.h
Normal file
109
src/httpserver/qhttpserverviewtraits.h
Normal file
@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERVIEWTRAITS_H
|
||||
#define QHTTPSERVERVIEWTRAITS_H
|
||||
|
||||
#include <QtHttpServer/qhttpserverviewtraits_impl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QHttpServerRequest;
|
||||
class QHttpServerResponse;
|
||||
|
||||
namespace QtPrivate {
|
||||
|
||||
template <typename ViewHandler, bool DisableStaticAssert>
|
||||
struct AfterRequestViewTraitsHelper : ViewTraits<ViewHandler, DisableStaticAssert> {
|
||||
using VTraits = ViewTraits<ViewHandler, DisableStaticAssert>;
|
||||
using FunctionTraits = typename VTraits::FTraits;
|
||||
|
||||
static_assert(DisableStaticAssert ||
|
||||
FunctionTraits::ArgumentCount == 2 ||
|
||||
FunctionTraits::ArgumentCount == 1,
|
||||
"ViewHandler arguments error: "
|
||||
"afterRequest can only accept QHttpServerResponse and QHttpServerRequest");
|
||||
|
||||
static_assert(DisableStaticAssert ||
|
||||
std::is_same<typename FunctionTraits::ReturnType,
|
||||
QHttpServerResponse>::value,
|
||||
"ViewHandler return type error: "
|
||||
"Return type can only be QHttpServerResponse");
|
||||
|
||||
template<int I>
|
||||
struct ArgumentChecker {
|
||||
using IsRequest = typename VTraits::template Special<I, const QHttpServerRequest &>;
|
||||
static_assert(IsRequest::AssertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerRequest can only be passed as a const reference");
|
||||
|
||||
using IsResponse = typename VTraits::template Special<I, QHttpServerResponse &&>;
|
||||
static_assert(IsResponse::AssertCondition,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerResponse can only be passed as a universal reference");
|
||||
|
||||
using IsSpecial = CheckAny<IsRequest, IsResponse>;
|
||||
|
||||
static constexpr bool Valid = IsSpecial::Valid;
|
||||
static constexpr bool StaticAssert = IsSpecial::StaticAssert;
|
||||
};
|
||||
|
||||
struct Arguments {
|
||||
template<int ... I>
|
||||
struct ArgumentsReturn {
|
||||
template<int Idx>
|
||||
using Arg = ArgumentChecker<Idx>;
|
||||
static constexpr bool Valid = QtPrivate::StaticMath::And::eval(Arg<I>::Valid...);
|
||||
static constexpr bool StaticAssert = QtPrivate::StaticMath::And::eval(
|
||||
Arg<I>::StaticAssert...);
|
||||
using Last = Arg<FunctionTraits::ArgumentIndexMax>;
|
||||
static constexpr std::size_t Count = FunctionTraits::ArgumentCount;
|
||||
};
|
||||
|
||||
template<int ... I>
|
||||
static constexpr ArgumentsReturn<I...> eval(QtPrivate::IndexesList<I...>) noexcept
|
||||
{
|
||||
return ArgumentsReturn<I...>{};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace QtPrivate
|
||||
|
||||
template <typename ViewHandler, bool DisableStaticAssert = false>
|
||||
struct QHttpServerAfterRequestViewTraits
|
||||
{
|
||||
using Helpers = typename QtPrivate::AfterRequestViewTraitsHelper<ViewHandler, DisableStaticAssert>;
|
||||
using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{}));
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERVIEWTRAITS_H
|
194
src/httpserver/qhttpserverviewtraits_impl.h
Normal file
194
src/httpserver/qhttpserverviewtraits_impl.h
Normal file
@ -0,0 +1,194 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtHttpServer module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QHTTPSERVERVIEWTRAITS_IMPL_H
|
||||
#define QHTTPSERVERVIEWTRAITS_IMPL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
#include <QtCore/qobjectdefs.h>
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtPrivate {
|
||||
|
||||
template<typename T>
|
||||
struct RemoveCVRef
|
||||
{
|
||||
using Type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
};
|
||||
|
||||
|
||||
template<bool classMember, typename ReturnT, typename ... Args>
|
||||
struct FunctionTraitsHelper
|
||||
{
|
||||
static constexpr const int ArgumentCount = sizeof ... (Args);
|
||||
static constexpr const int ArgumentIndexMax = ArgumentCount - 1;
|
||||
static constexpr const bool IsClassMember = classMember;
|
||||
using ReturnType = ReturnT;
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using Type = typename std::tuple_element<I, std::tuple<Args...>>::type;
|
||||
|
||||
using CleanType = typename QtPrivate::RemoveCVRef<Type>::Type;
|
||||
|
||||
static constexpr bool Defined = QMetaTypeId2<CleanType>::Defined;
|
||||
};
|
||||
};
|
||||
|
||||
template<bool classMember, typename ReturnT>
|
||||
struct FunctionTraitsHelper<classMember, ReturnT>
|
||||
{
|
||||
static constexpr const int ArgumentCount = 0;
|
||||
static constexpr const int ArgumentIndexMax = -1;
|
||||
static constexpr const bool IsClassMember = classMember;
|
||||
using ReturnType = ReturnT;
|
||||
|
||||
template <int I>
|
||||
struct Arg {
|
||||
using Type = std::false_type;
|
||||
using CleanType = Type;
|
||||
static constexpr bool Defined = QMetaTypeId2<CleanType>::Defined;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct FunctionTraits;
|
||||
|
||||
template<typename T>
|
||||
struct FunctionTraits : public FunctionTraits<decltype(&T::operator())>{};
|
||||
|
||||
template<typename ReturnT, typename ... Args>
|
||||
struct FunctionTraits<ReturnT (*)(Args...)>
|
||||
: public FunctionTraitsHelper<false, ReturnT, Args...>
|
||||
{
|
||||
};
|
||||
|
||||
template<class ReturnT, class ClassT, class ...Args>
|
||||
struct FunctionTraits<ReturnT (ClassT::*)(Args...) const>
|
||||
: public FunctionTraitsHelper<true, ReturnT, Args...>
|
||||
{
|
||||
using classType = ClassT;
|
||||
};
|
||||
|
||||
struct StaticMath {
|
||||
template <template<typename> class Predicate, bool defaultValue>
|
||||
struct Loop {
|
||||
static constexpr bool eval() noexcept {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
template<typename T, typename ... N>
|
||||
static constexpr T eval(const T it, N ...n) noexcept {
|
||||
return Predicate<T>::eval(it, eval(n...));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SumPredicate {
|
||||
static constexpr T eval(const T rs, const T ls) noexcept
|
||||
{
|
||||
return rs + ls;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct AndPredicate {
|
||||
static constexpr T eval(const T rs, const T ls) noexcept
|
||||
{
|
||||
return rs && ls;
|
||||
}
|
||||
};
|
||||
|
||||
using Sum = Loop<SumPredicate, false>;
|
||||
using And = Loop<AndPredicate, true>;
|
||||
using Or = Sum;
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct CheckAny {
|
||||
static constexpr bool Value = StaticMath::Or::eval(T::Value...);
|
||||
static constexpr bool Valid = StaticMath::Or::eval(T::Valid...);
|
||||
static constexpr bool StaticAssert = StaticMath::Or::eval(T::StaticAssert...);
|
||||
};
|
||||
|
||||
template<typename ViewHandler, bool DisableStaticAssert>
|
||||
struct ViewTraits {
|
||||
using FTraits = FunctionTraits<ViewHandler>;
|
||||
using ArgumentIndexes = typename Indexes<FTraits::ArgumentCount>::Value;
|
||||
|
||||
template<int I, typename Special>
|
||||
struct SpecialHelper {
|
||||
using Arg = typename FTraits::template Arg<I>;
|
||||
using CleanSpecialT = typename RemoveCVRef<Special>::Type;
|
||||
|
||||
static constexpr bool TypeMatched = std::is_same<typename Arg::CleanType, CleanSpecialT>::value;
|
||||
static constexpr bool TypeCVRefMatched = std::is_same<typename Arg::Type, Special>::value;
|
||||
|
||||
static constexpr bool ValidPosition =
|
||||
(I == FTraits::ArgumentIndexMax ||
|
||||
I == FTraits::ArgumentIndexMax - 1);
|
||||
static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition;
|
||||
|
||||
static constexpr bool AssertCondition =
|
||||
DisableStaticAssert || !TypeMatched || TypeCVRefMatched;
|
||||
|
||||
static constexpr bool AssertConditionOrder =
|
||||
DisableStaticAssert || !TypeMatched || ValidPosition;
|
||||
|
||||
static constexpr bool StaticAssert = AssertCondition && AssertConditionOrder;
|
||||
|
||||
static_assert(AssertConditionOrder,
|
||||
"ViewHandler arguments error: "
|
||||
"QHttpServerRequest or QHttpServerResponder"
|
||||
" can only be the last argument");
|
||||
};
|
||||
|
||||
template<int I, typename T>
|
||||
struct Special {
|
||||
using Helper = SpecialHelper<I, T>;
|
||||
static constexpr bool Value = Helper::TypeMatched;
|
||||
static constexpr bool Valid = Helper::ValidAll;
|
||||
static constexpr bool StaticAssert = Helper::StaticAssert;
|
||||
static constexpr bool AssertCondition = Helper::AssertCondition;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace QtPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QHTTPSERVERVIEWTRAITS_IMPL_H
|
@ -129,6 +129,7 @@ private slots:
|
||||
void routeExtraHeaders();
|
||||
void invalidRouterArguments();
|
||||
void checkRouteLambdaCapture();
|
||||
void afterRequest();
|
||||
|
||||
private:
|
||||
void checkReply(QNetworkReply *reply, const QString &response);
|
||||
@ -289,6 +290,10 @@ void tst_QHttpServer::initTestCase()
|
||||
return resp;
|
||||
});
|
||||
|
||||
httpserver.afterRequest([] (QHttpServerResponse &&resp) {
|
||||
return std::move(resp);
|
||||
});
|
||||
|
||||
quint16 port = httpserver.listen();
|
||||
if (!port)
|
||||
qCritical() << "Http server listen failed";
|
||||
@ -870,6 +875,36 @@ void tst_QHttpServer::checkRouteLambdaCapture()
|
||||
return;
|
||||
}
|
||||
|
||||
void tst_QHttpServer::afterRequest()
|
||||
{
|
||||
httpserver.afterRequest([] (QHttpServerResponse &&resp,
|
||||
const QHttpServerRequest &request) {
|
||||
if (request.url().path() == "/test-after-request")
|
||||
resp.setHeader("Arguments-Order-1", "resp, request");
|
||||
|
||||
return std::move(resp);
|
||||
});
|
||||
|
||||
httpserver.afterRequest([] (const QHttpServerRequest &request,
|
||||
QHttpServerResponse &&resp) {
|
||||
if (request.url().path() == "/test-after-request")
|
||||
resp.setHeader("Arguments-Order-2", "request, resp");
|
||||
|
||||
return std::move(resp);
|
||||
});
|
||||
|
||||
const QUrl requestUrl(urlBase.arg("/test-after-request"));
|
||||
auto reply = networkAccessManager.get(QNetworkRequest(requestUrl));
|
||||
|
||||
QTRY_VERIFY(reply->isFinished());
|
||||
|
||||
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), "application/x-empty");
|
||||
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 404);
|
||||
QCOMPARE(reply->rawHeader("Arguments-Order-1"), "resp, request");
|
||||
QCOMPARE(reply->rawHeader("Arguments-Order-2"), "request, resp");
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void tst_QHttpServer::checkReply(QNetworkReply *reply, const QString &response) {
|
||||
QTRY_VERIFY(reply->isFinished());
|
||||
|
||||
|
@ -252,8 +252,8 @@ void tst_QHttpServerRouter::viewHandlerNoArg()
|
||||
"viewOneArg: Args::Last::Valid");
|
||||
static_assert(Args::Last::StaticAssert,
|
||||
"viewOneArg: Args::Last::StaticAssert");
|
||||
static_assert(Args::Last::isType<std::false_type>(),
|
||||
"viewNonArg: Args::Last::isType<std::false_type>()");
|
||||
static_assert(std::is_same<Args::Last::Type, std::false_type>::value,
|
||||
"viewNonArg: std::is_same<Args::Last::Type, std::false_type>");
|
||||
|
||||
using Arg1 = typename Args::template Arg<1>;
|
||||
static_assert(Arg1::IsRequest::Value == 0,
|
||||
@ -272,8 +272,8 @@ void tst_QHttpServerRouter::viewHandlerNoArg()
|
||||
"viewOneArg: Args::Arg<1>::Valid");
|
||||
static_assert(Arg1::StaticAssert,
|
||||
"viewOneArg: Args::Arg<1>::Valid::StaticAssert");
|
||||
static_assert(Arg1::isType<std::false_type>(),
|
||||
"viewNonArg: Args::Arg<1>::isType<std::false_type>()");
|
||||
static_assert(std::is_same<Arg1::Type, std::false_type>::value,
|
||||
"viewNonArg: std::is_same<Args::Arg<1>::Type, std::false_type>");
|
||||
|
||||
static_assert(Args::Valid, "viewNonArg: Args::Valid");
|
||||
static_assert(Args::StaticAssert, "viewNonArg: Args::StaticAssert");
|
||||
@ -313,8 +313,8 @@ void tst_QHttpServerRouter::viewHandlerOneArg()
|
||||
"viewOneArg: Args::Last::Valid");
|
||||
static_assert(Args::Last::StaticAssert,
|
||||
"viewOneArg: Args::Last::StaticAssert");
|
||||
static_assert(Args::Last::isType<const quint64 &>(),
|
||||
"viewNonArg: Args::Last::isType<const quint64 &>()");
|
||||
static_assert(std::is_same<Args::Last::Type, const quint64 &>::value,
|
||||
"viewNonArg: std::is_same<Args::Last::Type, const quint64 &>");
|
||||
static_assert(Args::Valid, "viewOneArg: Args::Valid");
|
||||
static_assert(Args::StaticAssert, "viewOneArg: Args::StaticAssert");
|
||||
}
|
||||
@ -355,8 +355,8 @@ void tst_QHttpServerRouter::viewHandlerTwoArgs()
|
||||
"viewTwoArgs: Args::Arg0::Valid");
|
||||
static_assert(Arg0::StaticAssert,
|
||||
"viewTwoArgs: Args::Arg0::StaticAssert");
|
||||
static_assert(Arg0::isType<const quint64 &>(),
|
||||
"viewNonArg: Args::Arg0::isType<const quint64>()");
|
||||
static_assert(std::is_same<Arg0::Type, const quint64 &>::value,
|
||||
"viewNonArg: std::is_same<Args::Arg0::Type, const quint64>");
|
||||
|
||||
using Arg1 = typename Args::template Arg<1>;
|
||||
static_assert(Arg1::IsRequest::Value == 0,
|
||||
@ -380,8 +380,8 @@ void tst_QHttpServerRouter::viewHandlerTwoArgs()
|
||||
// StaticAssert is disabled in tests
|
||||
static_assert(Arg1::StaticAssert,
|
||||
"viewOneArg: Args::Arg1::StaticAssert");
|
||||
static_assert(Arg1::isType<const QHttpServerResponder &>(),
|
||||
"viewTwoArgs: Args::Arg1::isType<const QHttpServerResponder &>>()");
|
||||
static_assert(std::is_same<Arg1::Type, const QHttpServerResponder &>::value,
|
||||
"viewTwoArgs: std::is_same<Args::Arg1::Type, const QHttpServerResponder &>)");
|
||||
|
||||
static_assert(Args::Valid == 0, "viewTwoArgs: Args::Valid == 0");
|
||||
// StaticAssert is disabled in tests
|
||||
@ -422,8 +422,8 @@ void tst_QHttpServerRouter::viewHandlerResponder()
|
||||
"viewResponder: Args::Last::Valid");
|
||||
static_assert(Args::Last::StaticAssert,
|
||||
"viewResponder: Args::Last::StaticAssert");
|
||||
static_assert(Args::Last::isType<QHttpServerResponder &&>(),
|
||||
"viewNonArg: Args::Last::isType<QHttpServerResponder &&>()");
|
||||
static_assert(std::is_same<Args::Last::Type, QHttpServerResponder &&>::value,
|
||||
"viewNonArg: std::is_same<Args::Last::Type, QHttpServerResponder &&>");
|
||||
static_assert(Args::Valid, "viewResponder: Args::Valid");
|
||||
static_assert(Args::StaticAssert, "viewResponder: Args::StaticAssert");
|
||||
}
|
||||
@ -462,8 +462,8 @@ void tst_QHttpServerRouter::viewHandlerRequest()
|
||||
"viewResponder: Args::Last::Valid");
|
||||
static_assert(Args::Last::StaticAssert,
|
||||
"viewResponder: Args::Last::StaticAssert");
|
||||
static_assert(Args::Last::isType<const QHttpServerRequest &>(),
|
||||
"viewNonArg: Args::Last::isType<const QHttpServerRequest &>()");
|
||||
static_assert(std::is_same<Args::Last::Type, const QHttpServerRequest &>::value,
|
||||
"viewNonArg: std::is_same<Args::Last::Type, const QHttpServerRequest &>");
|
||||
static_assert(Args::Valid, "viewResponder: Args::Valid");
|
||||
static_assert(Args::StaticAssert, "viewResponder: Args::StaticAssert");
|
||||
}
|
||||
@ -505,8 +505,8 @@ void tst_QHttpServerRouter::viewHandlerLastTwoSpecials()
|
||||
// StaticAssert is disabled in tests
|
||||
static_assert(Arg0::StaticAssert,
|
||||
"viewTwoSpecialArgs: Args::Arg0::StaticAssert");
|
||||
static_assert(Arg0::isType<const QHttpServerRequest &>(),
|
||||
"viewNonArg: Args::Arg0::isType<const QHttpServerRequest &>()");
|
||||
static_assert(std::is_same<Arg0::Type, const QHttpServerRequest &>::value,
|
||||
"viewNonArg: std::is_same<Args::Arg0::Type, const QHttpServerRequest &>");
|
||||
|
||||
using Arg1 = typename Args::template Arg<1>;
|
||||
static_assert(Arg1::IsRequest::Value == 0,
|
||||
@ -529,8 +529,8 @@ void tst_QHttpServerRouter::viewHandlerLastTwoSpecials()
|
||||
"viewTwoSpecialArgs: Args::Arg1::Valid");
|
||||
static_assert(Arg1::StaticAssert,
|
||||
"viewTwoSpecialArgs: Args::Arg1::StaticAssert");
|
||||
static_assert(Arg1::isType<QHttpServerResponder &&>(),
|
||||
"viewTwoSpecialArgs: Args::Arg1::isType<QHttpServerResponder &&>()");
|
||||
static_assert(std::is_same<Arg1::Type, QHttpServerResponder &&>::value,
|
||||
"viewTwoSpecialArgs: std::is_same<Args::Arg1::Type, QHttpServerResponder &&>");
|
||||
|
||||
static_assert(Args::Valid, "viewTwoSpecialArgs: Args::Valid");
|
||||
// StaticAssert is disabled in tests
|
||||
|
Loading…
x
Reference in New Issue
Block a user