// Copyright (C) 2020 Mikhail Svetkin // Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef QHTTPSERVER_H #define QHTTPSERVER_H #include #include #include #include #include #include #if QT_CONFIG(future) # include #endif #include #include QT_BEGIN_NAMESPACE class QHttpServerRequest; class QHttpServerPrivate; class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer { Q_OBJECT Q_DECLARE_PRIVATE(QHttpServer) template struct VariadicTypeAt { using Type = typename std::tuple_element>::type; }; template struct VariadicTypeLast { using Type = typename VariadicTypeAt::Type; }; template static constexpr bool dependent_false_v = false; template using ResponseType = #if QT_CONFIG(future) std::conditional_t< std::is_same_v, T>, QFuture, QHttpServerResponse >; #else QHttpServerResponse; #endif public: explicit QHttpServer(QObject *parent = nullptr); ~QHttpServer(); QHttpServerRouter *router(); template bool route(Args && ... args) { using ViewHandler = typename VariadicTypeLast::Type; using ViewTraits = QHttpServerRouterViewTraits; static_assert(ViewTraits::Arguments::StaticAssert, "ViewHandler arguments are in the wrong order or not supported"); return routeHelper( QtPrivate::makeIndexSequence{}, std::forward(args)...); } template void afterRequest(ViewHandler &&viewHandler) { using ViewTraits = QHttpServerAfterRequestViewTraits; static_assert(ViewTraits::Arguments::StaticAssert, "ViewHandler arguments are in the wrong order or not supported"); afterRequestHelper(std::move(viewHandler)); } using MissingHandler = std::function; void setMissingHandler(MissingHandler handler); private: using AfterRequestHandler = std::function; template void afterRequestHelper(ViewHandler &&viewHandler) { auto handler = [viewHandler](QHttpServerResponse &&resp, const QHttpServerRequest &request) { if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { if constexpr (ViewTraits::Arguments::Count == 2) return std::move(viewHandler(std::move(resp), request)); else static_assert(dependent_false_v); } else if constexpr (ViewTraits::Arguments::Last::IsResponse::Value) { if constexpr (ViewTraits::Arguments::Count == 1) return std::move(viewHandler(std::move(resp))); else if constexpr (ViewTraits::Arguments::Count == 2) return std::move(viewHandler(request, std::move(resp))); else static_assert(dependent_false_v); } else { static_assert(dependent_false_v); } }; afterRequestImpl(std::move(handler)); } void afterRequestImpl(AfterRequestHandler afterRequestHandler); template bool routeHelper(QtPrivate::IndexesList, Args &&... args) { return routeImpl::Type...>(std::forward(args)...); } template bool routeImpl(Args &&...args, ViewHandler &&viewHandler) { auto routerHandler = [this, viewHandler = std::forward(viewHandler)]( const QRegularExpressionMatch &match, const QHttpServerRequest &request, QHttpServerResponder &&responder) { auto boundViewHandler = router()->bindCaptured(viewHandler, match); responseImpl(boundViewHandler, request, std::move(responder)); }; auto rule = std::make_unique(std::forward(args)..., std::move(routerHandler)); return router()->addRule(std::move(rule)); } template void responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QHttpServerResponder &&responder) { if constexpr (ViewTraits::Arguments::PlaceholdersCount == 0) { ResponseType response(boundViewHandler()); sendResponse(std::move(response), request, std::move(responder)); } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 1) { if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { ResponseType response(boundViewHandler(request)); sendResponse(std::move(response), request, std::move(responder)); } else { static_assert(std::is_same_v, "Handlers with responder argument must have void return type."); boundViewHandler(std::move(responder)); } } else if constexpr (ViewTraits::Arguments::PlaceholdersCount == 2) { static_assert(std::is_same_v, "Handlers with responder argument must have void return type."); if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { boundViewHandler(std::move(responder), request); } else { boundViewHandler(request, std::move(responder)); } } else { static_assert(dependent_false_v); } } bool handleRequest(const QHttpServerRequest &request, QHttpServerResponder &responder) override final; void missingHandler(const QHttpServerRequest &request, QHttpServerResponder &&responder) override final; void sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request, QHttpServerResponder &&responder); #if QT_CONFIG(future) void sendResponse(QFuture &&response, const QHttpServerRequest &request, QHttpServerResponder &&responder); #endif }; QT_END_NAMESPACE #endif // QHTTPSERVER_H