// 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 #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 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 using MissingHandlerPrototype = void (*)(const QHttpServerRequest &request, QHttpServerResponder &responder); template using if_missinghandler_prototype_compatible = typename std::enable_if< QtPrivate::AreFunctionsCompatible::value, bool>::type; using AfterRequestPrototype = void (*)(const QHttpServerRequest &request, QHttpServerResponse &response); template using if_after_request_prototype_compatible = typename std::enable_if< QtPrivate::AreFunctionsCompatible::value, bool>::type; public: explicit QHttpServer(QObject *parent = nullptr); ~QHttpServer() override; QHttpServerRouter *router(); const QHttpServerRouter *router() const; #ifdef Q_QDOC template Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, const QObject *context, Functor &&slot); template Rule *route(const QString &pathPattern, const QObject *context, Functor &&slot); template Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, Functor &&handler); template Rule *route(const QString &pathPattern, Functor &&handler); #else template Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, const typename QtPrivate::ContextTypeForFunctor::ContextType *context, ViewHandler &&viewHandler) { using ViewTraits = QHttpServerRouterViewTraits; static_assert(ViewTraits::Arguments::StaticAssert, "ViewHandler arguments are in the wrong order or not supported"); return routeImpl(pathPattern, method, context, std::forward(viewHandler)); } template Rule *route(const QString &pathPattern, const typename QtPrivate::ContextTypeForFunctor::ContextType *context, ViewHandler &&viewHandler) { using ViewTraits = QHttpServerRouterViewTraits; static_assert(ViewTraits::Arguments::StaticAssert, "ViewHandler arguments are in the wrong order or not supported"); return routeImpl(pathPattern, context, std::forward(viewHandler)); } template Rule *route(const QString &pathPattern, ViewHandler &&viewHandler) { return route(pathPattern, QHttpServerRequest::Method::AnyKnown, this, std::forward(viewHandler)); } template Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method, ViewHandler &&viewHandler) { return route(pathPattern, method, this, std::forward(viewHandler)); } #endif #ifdef Q_QDOC template void setMissingHandler(const QObject *context, Functor &&slot); #else template = true> void setMissingHandler(const typename QtPrivate::ContextTypeForFunctor::ContextType *context, Handler &&handler) { setMissingHandlerImpl(context, QtPrivate::makeCallableObject( std::forward(handler))); } #endif #ifdef Q_QDOC template void addAfterRequestHandler(const QObject *context, Functor &&slot); #else template = true> void addAfterRequestHandler(const typename QtPrivate::ContextTypeForFunctor::ContextType *context, Handler &&handler) { addAfterRequestHandlerImpl(context, QtPrivate::makeCallableObject( std::forward(handler))); } #endif void clearMissingHandler(); private: void setMissingHandlerImpl(const QObject *context, QtPrivate::QSlotObjectBase *handler); void addAfterRequestHandlerImpl(const QObject *context, QtPrivate::QSlotObjectBase *handler); template auto createRouteHandler(const typename QtPrivate::ContextTypeForFunctor::ContextType *context, ViewHandler &&viewHandler) { return [this, context, viewHandler]( const QRegularExpressionMatch &match, const QHttpServerRequest &request, QHttpServerResponder &responder) mutable { auto boundViewHandler = QHttpServerRouterRule::bindCaptured(context, std::forward(viewHandler), match); responseImpl(boundViewHandler, request, std::move(responder)); }; } template Rule *routeImpl(const QString &pathPattern, const typename QtPrivate::ContextTypeForFunctor::ContextType *context, ViewHandler &&viewHandler) { auto routerHandler = createRouteHandler(context, std::forward(viewHandler)); auto rule = std::make_unique(pathPattern, context, std::move(routerHandler)); return reinterpret_cast(router()->addRule(std::move(rule))); } template Rule *routeImpl(const QString &pathPattern, QHttpServerRequest::Methods method, const typename QtPrivate::ContextTypeForFunctor::ContextType *context, ViewHandler &&viewHandler) { auto routerHandler = createRouteHandler(context, std::forward(viewHandler)); auto rule = std::make_unique(pathPattern, method, context, std::move(routerHandler)); return reinterpret_cast(router()->addRule(std::move(rule))); } template void responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QHttpServerResponder &&responder) { if constexpr (ViewTraits::Arguments::SpecialsCount == 0) { ResponseType response(boundViewHandler()); sendResponse(std::move(response), request, std::move(responder)); } else if constexpr (ViewTraits::Arguments::SpecialsCount == 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(responder); } } else if constexpr (ViewTraits::Arguments::SpecialsCount == 2) { static_assert(std::is_same_v, "Handlers with responder argument must have void return type."); if constexpr (ViewTraits::Arguments::Last::IsRequest::Value) { boundViewHandler(responder, request); } else { boundViewHandler(request, responder); } } else { static_assert(dependent_false_v); } } bool handleRequest(const QHttpServerRequest &request, QHttpServerResponder &responder) override; void missingHandler(const QHttpServerRequest &request, QHttpServerResponder &responder) override; 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