Update documentation to new API

Pick-to: 6.8
Task-Id: QTBUG-128113
Change-Id: I05c0ee722033f82e693a10f66f5877e3a7fb5706
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Matthias Rauter 2024-08-19 21:00:58 +02:00
parent 945a3c209c
commit a329eb9a17
9 changed files with 376 additions and 178 deletions

View File

@ -27,7 +27,8 @@
This can be simplified even further by using the QHttpServer class.
The QHttpServer class is a subclass of QAbstractHttpServer and defines an
overloaded route function to bind callables to different incoming URLs,
and an \l{QHttpServer::}{afterRequest()} function to process the response further.
and an \l{QHttpServer::}{addAfterRequestHandler()} function to process the response
further.
Runtime logging can be configured as described \l{qthttpserver-logging.html}{here}.

View File

@ -18,8 +18,8 @@ of several different incoming URLs. For one of the URLs, "/auth",
In the above example \c QSslConfiguration is used to show how to create
an SSL configuration for a QHttpServer to serve HTTPS traffic.
\snippet simple/main.cpp Using afterRequest()
The above example shows how to use the \c afterRequest() function of the
\snippet simple/main.cpp Using addAfterRequestHandler()
The above example shows how to use the \c addAfterRequestHandler() function of the
QHttpServer to change the QHttpServerResponse object after it has been handled
by the \c route() function. It demonstrates how HTTP headers can be added to the
response.

View File

@ -104,13 +104,13 @@ int main(int argc, char *argv[])
return std::move(resp);
});
//! [Using afterRequest()]
//! [Using addAfterRequestHandler()]
httpServer.addAfterRequestHandler(&httpServer, [](const QHttpServerRequest &, QHttpServerResponse &resp) {
auto h = resp.headers();
h.append(QHttpHeaders::WellKnownHeader::Server, "Qt HTTP Server");
resp.setHeaders(std::move(h));
});
//! [Using afterRequest()]
//! [Using addAfterRequestHandler()]
auto tcpserver = std::make_unique<QTcpServer>();
if (!tcpserver->listen() || !httpServer.bind(tcpserver.get())) {

View File

@ -103,6 +103,9 @@ void QAbstractHttpServerPrivate::handleNewLocalConnections()
Subclass this class and override handleRequest() and missingHandler() to
create an HTTP server. Use bind() to start listening to all the incoming
connections to a server.
This is a low level API, see \l QHttpServer for a highler level API to
implement an HTTP server.
*/
/*!
@ -113,7 +116,7 @@ QAbstractHttpServer::QAbstractHttpServer(QObject *parent)
{}
/*!
\internal
Destroys an instance of QAbstractHttpServer.
*/
QAbstractHttpServer::~QAbstractHttpServer()
= default;
@ -164,8 +167,6 @@ QList<quint16> QAbstractHttpServer::serverPorts() const
the \a server before calling this function. If \a server is not
listening, nothing will happen and \c false will be returned.
If the \a server is nullptr false is returned.
If successful the \a server will be parented to this HTTP server
and \c true is returned.
@ -232,7 +233,7 @@ bool QAbstractHttpServer::bind(QLocalServer *server)
#endif
/*!
Returns list of child TCP servers of this HTTP server.
Returns the TCP servers of this HTTP server.
\sa serverPorts()
*/
@ -243,7 +244,7 @@ QList<QTcpServer *> QAbstractHttpServer::servers() const
#if QT_CONFIG(localserver)
/*!
Returns list of child TCP servers of this HTTP server.
Returns the local servers of this HTTP server.
\sa serverPorts()
*/
@ -323,7 +324,7 @@ QAbstractHttpServer::verifyWebSocketUpgrade(const QHttpServerRequest &request) c
it. If no handlers are registered or all return \c PassToNext,
missingHandler() is called. The callback functions are executed in the
order they are registered. The callbacks cannot call
registerWebSocketUpgradeVerifier().
addWebSocketUpgradeVerifier().
\note The WebSocket upgrades fail if no callbacks has been registered.
\note This overload participates in overload resolution only if the
@ -331,7 +332,7 @@ QAbstractHttpServer::verifyWebSocketUpgrade(const QHttpServerRequest &request) c
and returns a QHttpServerWebSocketUpgradeResponse.
\code
server.registerWebSocketUpgradeVerifier(
server.addWebSocketUpgradeVerifier(
&server, [](const QHttpServerRequest &request) {
if (request.url().path() == "/allowed"_L1)
return QHttpServerWebSocketUpgradeResponse::accept();
@ -366,7 +367,7 @@ void QAbstractHttpServer::addWebSocketUpgradeVerifierImpl(const QObject *context
/*!
\fn QAbstractHttpServer::handleRequest(const QHttpServerRequest &request,
QHttpServerResponder &responder)
Overload this function to handle each incoming \a request, by examining
Override this function to handle each incoming \a request, by examining
the \a request and sending the appropriate response back to \a responder.
Return \c true if the \a request was handled successfully. If this method
returns \c false, missingHandler() will be called afterwards.
@ -376,15 +377,16 @@ void QAbstractHttpServer::addWebSocketUpgradeVerifierImpl(const QObject *context
/*!
\fn QAbstractHttpServer::missingHandler(const QHttpServerRequest &request,
QHttpServerResponder &&responder)
QHttpServerResponder &responder)
This function is called whenever handleRequest() returns \c false, or if
there is a WebSocket upgrade attempt and either there are no connections
to newWebSocketConnection() or there are no matching WebSocket verifiers.
The \a request and \a responder parameters are the same as
handleRequest() was called with.
Override this function to handle each incoming \a request that was not
handled by \l handleRequest(). This function is called whenever \l
handleRequest() returns \c false, or if there is a WebSocket upgrade
attempt and either there are no connections to newWebSocketConnection() or
there are no matching WebSocket verifiers. The \a request and \a responder
parameters are the same as handleRequest() was called with.
\sa handleRequest(), registerWebSocketUpgradeVerifier()
\sa handleRequest(), addWebSocketUpgradeVerifier()
*/
#if QT_CONFIG(ssl)

View File

@ -44,6 +44,16 @@ void QHttpServerPrivate::callMissingHandler(const QHttpServerRequest &request,
\inmodule QtHttpServer
\brief QHttpServer is a simplified API for QAbstractHttpServer and QHttpServerRouter.
QHttpServer allows to create a simple Http server by setting a range of
request handlers.
The \l route function can be used to conveniently add rules to
the servers \l QHttpServerRouter. To register a handler to be called after
every request use \l addAfterRequestHandler and to register a handler for
all unhandled requests use \l setMissingHandler.
Minimal example:
\code
QHttpServer server;
@ -52,14 +62,12 @@ void QHttpServerPrivate::callMissingHandler(const QHttpServerRequest &request,
return "hello world";
});
auto tcpserver = std::make_unique<QTcpServer>();
auto tcpserver = new QTcpServer();
if (!tcpserver->listen() || !server.bind(tcpserver.get())) {
qDebug() << "Failed listening";
delete tcpserver;
return -1;
}
quint16 port = tcpserver->serverPort();
tcpserver.release();
qDebug() << "Listening on port" << port;
qDebug() << "Listening on port" << tcpserver->serverPort();
\endcode
*/
@ -72,46 +80,83 @@ QHttpServer::QHttpServer(QObject *parent)
{
}
/*! \fn template<typename Rule = QHttpServerRouterRule, typename ... Args> bool QHttpServer::route(Args && ... args)
/*! \fn template <typename Rule = QHttpServerRouterRule, typename Functor> Rule *QHttpServer::route(const QString &pathPattern, QHttpServerRequest::Methods method, const QObject *receiver, Functor &&slot)
This function is just a wrapper to simplify the router API.
This is a convenience method to add a new \c Rule to the server's
\l{QHttpServerRouter}. The Rule template parameter can be any custom class
derived from QHttpServerRouterRule.
This function takes variadic arguments \a args. The last argument is a
callback (\c{ViewHandler}). The remaining arguments are used to create a
new \c Rule (the default is QHttpServerRouterRule). This is in turn added
to the QHttpServerRouter. It returns \c true if a new rule is created,
otherwise it returns \c false. This function must not be called from a
callback (\c{ViewHandler}).
This function takes a \a pathPattern and a \a method that represent a set
of requests and creates a new \l{QHttpServerRouterRule} (or custom Rule if
specified in the template parameters) that forwards all respective requests
to the provided \a receiver and \a slot. The rule is added to the
\l{router}. For details on valid patterns in \a pathPattern, see the
\l{QHttpServerRouterRule} documentation.
\c ViewHandler can be a function pointer, non-mutable lambda, or any
other copiable callable with const call operator. The callable can take two
optional special arguments: \c {const QHttpServerRequest&} and
\c {QHttpServerResponder&&}. These special arguments must be the last in
the parameter list, but in any order, and there can be none, one, or both
of them present. Only handlers with \c void return type can accept
\c {QHttpServerResponder&&} arguments.
\a slot can be a member function pointer of \a receiver. It can also be
a function pointer, a non-mutable lambda, or any other copiable callable
with const call operator. In that case \a receiver has to be a \l QObject
pointer. The rule will be valid for the lifetime duration of the \a
receiver. The receiver must share the same thread affinity as the
QHttpServer for the registration to be successful and for the rule to be
executed.
\note If a request was processed by a handler accepting \c {QHttpServerResponder&&}
as an argument, \c {afterRequest(ViewHandler &&viewHandler)} method won't be called.
Examples:
The slot can express its response with a return statement. The function has
to return QHttpServerResponse or any type that can be converted to
QHttpServerResponse. A large range of conversion constructors are available,
see \l{QHttpServerResponse}.
\code
QHttpServer server;
// Valid:
server.route("test", [] (const int page) { return ""; });
server.route("test", [] (const int page, const QHttpServerRequest &request) { return ""; });
server.route("test", [] (QHttpServerResponder &&responder) { return ""; });
// Invalid (compile time error):
server.route("test", [] (const QHttpServerRequest &request, const int page) { return ""; }); // request must be last
server.route("test", [] (QHttpServerRequest &request) { return ""; }); // request must be passed by const reference
server.route("test", [] (QHttpServerResponder &responder) { return ""; }); // responder must be passed by universal reference
server.route("/test", this, [] () { return ""; });
\endcode
Alternatively, an optional last function argument \c {QHttpServerResponder&}
can be provided on which the response has to be written. If the response is
written to a \c {QHttpServerResponder&} the function must return \c void.
\code
server.route("/test2", this, [] (QHttpServerResponder &responder) {
responder.write(QHttpServerResponder::StatusCode::Forbidden); });
\endcode
The slot can further have a \c {const QHttpServerRequest&} as a
second to last parameter to get detailed information on the request
\code
server.route("/test3", this, [] (const QHttpServerRequest &request,
QHttpServerResponder &responder) {
responder.write(req.body(), "text/plain"_ba);});
\endcode
Finally, the callback can contain an arbitrary amount of copiable
parameters that are registered with the QHttpServerRouter::converters. By
default, these are most integer types, float, double, QString, QByteArray,
and QUrl. Additional converters can be registered, see
\l{QHttpServerRouter::addConverter}. These parameters must have a
corresponding placeholder in the \a pathPattern. For details on
placeholders and pathPattern see \l{QHttpServerRouterRule}.
\code
QHttpServer server;
server.route("/test/<arg>", this, [] (const int page) { return ""; });
\endcode
This function returns, if successful, a pointer to the newly created Rule,
otherwise a \c nullptr. The pointer can be used to set parameters on any
custom \l{QHttpServerRouter} class:
\code
auto rule = server.route<MyRule>("/test", this, [] () {return "";});
rule->setParameter("test");
\endcode
. This function must not be called from any \l route callback.
\note If a request was processed by a handler accepting \c
{QHttpServerResponder&} as an argument, none of the after request handlers
(see \l addAfterRequestHandler) will be called.
Requests are processed sequentially inside the \c {QHttpServer}'s thread
by default. The request handler may return \c {QFuture<QHttpServerResponse>}
if asynchronous processing is desired:
@ -126,50 +171,41 @@ QHttpServer::QHttpServer(QObject *parent)
The body of \c QFuture is executed asynchronously, but all the network
communication is executed sequentially in the thread the \c {QHttpServer}
belongs to. The \c {QHttpServerResponder&&} special argument is not
belongs to. The \c {QHttpServerResponder&} special argument is not
available for routes returning a \c {QFuture}.
\sa QHttpServerRouter::addRule, afterRequest
\sa QHttpServerRouter::addRule, addAfterRequestHandler
*/
/*! \fn template<typename ViewHandler> void QHttpServer::afterRequest(ViewHandler &&viewHandler)
Register a function to be run after each request.
/*! \fn template <typename Rule = QHttpServerRouterRule, typename Functor> Rule *QHttpServer::route(const QString &pathPattern, const QObject *receiver, Functor &&slot)
\note This function won't be called for requests, processed by handlers
with \c {QHttpServerResponder&&} argument.
\overload
The \a viewHandler argument can be a function pointer, non-mutable lambda,
or any other copiable callable with const call operator. The callable
can take one or two optional arguments: \c {QHttpServerResponse &&} and
\c {const QHttpServerRequest &}. If both are given, they can be in either
order.
Overload of \l QHttpServer::route to create a Rule for \a pathPattern and
\l QHttpServerRequest::Method::AnyKnown. All requests are forwarded
to \a receiver and \a slot.
*/
Examples:
/*! \fn template <typename Rule = QHttpServerRouterRule, typename Functor> Rule *QHttpServer::route(const QString &pathPattern, QHttpServerRequest::Methods method, Functor &&handler)
\code
\overload
QHttpServer server;
Overload of \l QHttpServer::route to create a Rule for \a pathPattern and
\a method. All requests are forwarded to \a handler, which can be a
function pointer, a non-mutable lambda, or any other copiable callable with
const call operator. The rule will be valid until the QHttpServer is
destroyed.
*/
// 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); }
/*! \fn template <typename Rule = QHttpServerRouterRule, typename Functor> Rule *QHttpServer::route(const QString &pathPattern, Functor &&handler)
// 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);
}
\overload
\endcode
Overload of \l QHttpServer::route to create a Rule for \a pathPattern and
\l QHttpServerRequest::Method::AnyKnown. All requests are forwarded to \a
handler, which can be a function pointer, a non-mutable lambda, or any
other copiable callable with const call operator. The rule will be valid
until the QHttpServer is destroyed.
*/
/*!
@ -197,15 +233,18 @@ const QHttpServerRouter *QHttpServer::router() const
return &d->router;
}
/*! \fn template <typename Handler, QHttpServer::if_missinghandler_prototype_compatible<Handler> = true>
void QHttpServer::setMissingHandler(typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context,
Handler &&handler)
/*! \fn template <typename Functor> void QHttpServer::setMissingHandler(const QObject *receiver, Functor &&slot)
Set a handler for unhandled requests.
Set a handler to call for unhandled paths.
All unhandled requests will be forwarded to the \a{receiver}'s \a slot.
The invocable passed as \a handler will be invoked on \a context for
each request that cannot be handled by any of registered route handlers.
The default one replies with status 404 Not Found.
The \a slot has to implement the signature \c{void (*)(const
QHttpServerRequest &, QHttpServerResponder &)}. The \a slot can also be a
function pointer, non-mutable lambda, or any other copiable callable with
const call operator. In that case the \a receiver will be a context object.
The handler will be valid until the receiver object is destroyed.
The default handler replies with status 404: Not Found.
*/
/*!
@ -230,6 +269,32 @@ void QHttpServer::clearMissingHandler()
d->missingHandler.slotObject.reset();
}
/*! \fn template <typename Functor> void QHttpServer::addAfterRequestHandler(const QObject *receiver, Functor &&slot)
Register a \a receiver and \a slot to be called after every request is
handled.
The \a slot has to implement the signature \c{void (*)(QHttpServerResponse&,
const QHttpServerRequest&)}.
The \a slot can also be a function pointer, non-mutable lambda, or any other
copiable callable with const call operator. In that case the \a receiver will
be a context object and the handler will be valid until the context
object is destroyed.
Example:
\code
QHttpServer server;
server.addAfterRequestHandler(&server, [] (QHttpServerResponse &resp, const QHttpServerRequest &req) {
resp.write(req.body(), "text/plain"_ba);
}
\endcode
\note These handlers won't be called for requests, processed by handlers
with \c {QHttpServerResponder&} argument.
*/
/*!
\internal
*/

View File

@ -62,6 +62,25 @@ public:
QHttpServerRouter *router();
const QHttpServerRouter *router() const;
#ifdef Q_QDOC
template <typename Rule = QHttpServerRouterRule, typename Functor>
Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method,
const QObject *receiver,
Functor &&slot);
template <typename Rule = QHttpServerRouterRule, typename Functor>
Rule *route(const QString &pathPattern,
const QObject *receiver,
Functor &&slot);
template <typename Rule = QHttpServerRouterRule, typename Functor>
Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method,
Functor &&handler);
template <typename Rule = QHttpServerRouterRule, typename Functor>
Rule *route(const QString &pathPattern,
Functor &&handler);
#else
template<typename Rule = QHttpServerRouterRule, typename ViewHandler>
Rule *route(const QString &pathPattern, QHttpServerRequest::Methods method,
const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context,
@ -101,7 +120,12 @@ public:
return route<Rule>(pathPattern, method,
this, std::forward<ViewHandler>(viewHandler));
}
#endif
#ifdef Q_QDOC
template <typename Functor>
void setMissingHandler(const QObject *receiver, Functor &&slot);
#else
template <typename Handler, if_missinghandler_prototype_compatible<Handler> = true>
void setMissingHandler(const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context,
Handler &&handler)
@ -110,7 +134,12 @@ public:
QtPrivate::makeCallableObject<MissingHandlerPrototype>(
std::forward<Handler>(handler)));
}
#endif
#ifdef Q_QDOC
template <typename Functor>
void addAfterRequestHandler(const QObject *receiver, Functor &&slot);
#else
template <typename Handler, if_after_request_prototype_compatible<Handler> = true>
void addAfterRequestHandler(const typename QtPrivate::ContextTypeForFunctor<Handler>::ContextType *context,
Handler &&handler)
@ -119,6 +148,7 @@ public:
QtPrivate::makeCallableObject<AfterRequestPrototype>(
std::forward<Handler>(handler)));
}
#endif
void clearMissingHandler();

View File

@ -50,13 +50,21 @@ static const QHash<QMetaType, QString> defaultConverters = {
\brief Provides functions to bind a URL to a \c ViewHandler.
\inmodule QtHttpServer
You can register \c ViewHandler as a callback for requests to a specific URL.
Variable parts in the route can be specified by the arguments in ViewHandler.
A QHttpServerRouter instance must not be modifed by its rules.
QHttpServerRouter is a class to distribute http requests to their
respective handlers with a rule based system.
You can register new \l{QHttpServerRouterRule}{QHttpServerRouterRules},
that represent a request path and the respective handler. Variable parts in
the route can be specified with placeholder in the request path. The
handler gets the placeholders value as a \l QRegularExpressionMatch. The
arguments can be of any type for which a \l{converters}{converter} is
available. The handler creation can be simplified with
QHttpServerRouterRule::bindCaptured. A QHttpServerRouter instance must not
be modifed by its rules.
\note This is a low-level routing API for an HTTP server.
See the following example:
Minimal example:
\code
auto pageView = [] (const quint64 page) {
@ -68,11 +76,11 @@ static const QHash<QMetaType, QString> defaultConverters = {
// register callback pageView on request "/page/<number>"
// for example: "/page/10", "/page/15"
router.addRoute<ViewHandler>(
router.addRule<ViewHandler>(
new QHttpServerRouterRule("/page/", [=] (QRegularExpressionMatch &match,
const QHttpServerRequest &,
QHttpServerResponder &&) {
auto boundView = router.bindCaptured(pageView, match);
auto boundView = QHttpServerRouterRule::bindCaptured(pageView, match);
// it calls pageView
boundView();
@ -82,13 +90,16 @@ static const QHash<QMetaType, QString> defaultConverters = {
/*! \fn template <typename Type> bool QHttpServerRouter::addConverter(QAnyStringView regexp)
Adds a new converter for type \e Type matching regular expression \a regexp,
and returns \c true if this was successful, otherwise returns \c false.
Adds a new converter for \e Type that can be parsed with \a regexp, and
returns \c true if this was successful, otherwise returns \c false. If
successful, the registered type can be used as argument in handlers for
\l{QHttpServerRouterRule}. The regular expression will be used to parse the
path pattern of the rule.
Automatically try to register an implicit converter from QString to \e Type.
If there is already a converter of type \e Type, that converter's regexp
is replaced with \a regexp.
Minimal example:
\code
struct CustomArg {
int data = 10;
@ -107,12 +118,12 @@ static const QHash<QMetaType, QString> defaultConverters = {
using ViewHandler = decltype(pageView);
auto rule = std::make_unique<QHttpServerRouterRule>(
"/<arg>/<arg>/log",
"/<arg>/log",
[&router, &pageView] (QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QHttpServerResponder &&responder) {
// Bind and call viewHandler with match's captured string and quint32:
router.bindCaptured(pageView, match)();
QHttpServerRouterRule::bindCaptured(pageView, match)();
});
router.addRule<ViewHandler>(std::move(rule));
@ -120,8 +131,9 @@ static const QHash<QMetaType, QString> defaultConverters = {
*/
/*! \fn template <typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> bool QHttpServerRouter::addRule(std::unique_ptr<QHttpServerRouterRule> rule)
Adds a new \a rule to the router.
Adds a new \a rule and returns \c true if this was successful.
Returns a pointer to the new rule if successful or \c nullptr otherwise.
Inside addRule, we determine ViewHandler arguments and generate a list of
their QMetaType::Type ids. Then we parse the URL and replace each \c <arg>
@ -144,36 +156,6 @@ static const QHash<QMetaType, QString> defaultConverters = {
\endcode
*/
/*! \fn template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>> typename ViewTraits::BindableType QHttpServerRouter::bindCaptured(ViewHandler &&handler, const QRegularExpressionMatch &match) const
Supplies the \a handler with arguments derived from a URL.
Returns the bound function that accepts whatever remaining arguments the handler may take,
supplying them to the handler after the URL-derived values.
Each match of the regex applied to the URL (as a string) is converted to
the type of the handler's parameter at its position, so that it can be
passed as \a match.
\code
QHttpServerRouter router;
auto pageView = [] (const QString &page, const quint32 num) {
qDebug("page: %s, num: %d", qPrintable(page), num);
};
using ViewHandler = decltype(pageView);
auto rule = std::make_unique<QHttpServerRouterRule>(
"/<arg>/<arg>/log",
[&router, &pageView] (QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QHttpServerResponder &&responder) {
// Bind and call viewHandler with match's captured string and quint32:
router.bindCaptured(pageView, match)();
});
router.addRule<ViewHandler>(std::move(rule));
\endcode
*/
QHttpServerRouterPrivate::QHttpServerRouterPrivate(QAbstractHttpServer *server)
: converters(defaultConverters), server(server)
{}
@ -181,7 +163,7 @@ QHttpServerRouterPrivate::QHttpServerRouterPrivate(QAbstractHttpServer *server)
/*!
Creates a QHttpServerRouter object with default converters.
\sa converters()
\sa converters
*/
QHttpServerRouter::QHttpServerRouter(QAbstractHttpServer *server)
: d_ptr(new QHttpServerRouterPrivate(server))
@ -194,10 +176,15 @@ QHttpServerRouter::~QHttpServerRouter()
{}
/*!
Adds a new converter for type \a metaType matching regular expression \a regexp.
Adds a new converter for \a metaType that can be parsed with \a regexp.
Having a converter for a \a metaType enables to use this type in a path
pattern of a \l QHttpServerRouterRule. The regular expression is used to
parse parameters of type \a metaType from the path pattern.
If there is already a converter of type \a metaType, that converter's regexp
is replaced with \a regexp.
If there is already a converter of type \a metaType, that converter's
regexp is replaced with \a regexp.
\sa converters, clearConverters
*/
void QHttpServerRouter::addConverter(QMetaType metaType, QAnyStringView regexp)
{
@ -207,6 +194,8 @@ void QHttpServerRouter::addConverter(QMetaType metaType, QAnyStringView regexp)
/*!
Removes the converter for type \a metaType.
\sa addConverter
*/
void QHttpServerRouter::removeConverter(QMetaType metaType)
{
@ -219,7 +208,7 @@ void QHttpServerRouter::removeConverter(QMetaType metaType)
\note clearConverters() does not set up default converters.
\sa converters()
\sa converters, addConverter
*/
void QHttpServerRouter::clearConverters()
{
@ -231,7 +220,9 @@ void QHttpServerRouter::clearConverters()
\fn const QHash<QMetaType, QString> &QHttpServerRouter::converters() const &
\fn QHash<QMetaType, QString> QHttpServerRouter::converters() &&
Returns a map of converter type and regexp.
Returns a map of converter types and regular expressions that are registered
with this QHttpServerRouter. These are the types that can be used in path
patterns of \l{QHttpServerRouterRule}{QHttpServerRouterRules}.
The following converters are available by default:
@ -249,6 +240,8 @@ void QHttpServerRouter::clearConverters()
\value QMetaType::QByteArray
\value QMetaType::QUrl
\value QMetaType::Void An empty converter.
\sa addConverter, clearConverters
*/
const QHash<QMetaType, QString> &QHttpServerRouter::converters() const &
{

View File

@ -23,33 +23,87 @@ Q_STATIC_LOGGING_CATEGORY(lcRouterRule, "qt.httpserver.router.rule")
\brief The QHttpServerRouterRule is the base class for QHttpServerRouter rules.
\inmodule QtHttpServer
Use QHttpServerRouterRule to specify expected request parameters:
QHttpServerRouterRule expresses the connection between a request path, an
HTTP request method, and the respective handler callback. The \l
QHttpServerRouter is a collection of such rules from which the handlers are
called if the path and request method match the request. The handler
callback must provide the response to the request.
\value path QUrl::path()
\value HTTP methods QHttpServerRequest::Methods
\value callback User-defined response callback
\section1 Path and Patterns
\note This is a low level API, see QHttpServer for higher level alternatives.
Every QHttpServerRouterRule contains a path or path pattern which defines
the paths for which it can provide a response through its handler. The path
can contain placeholders that are forwarded to the rule's handler. The
following examples of path patterns are shown with the \l
QHttpServer::route convenience method, but can also be provided to the
QHttpServerRouterRule constructor.
Example of QHttpServerRouterRule and QHttpServerRouter usage:
In the simplest case the path is a string with a leading "/":
\code
QHttpServer server;
server.route("/user", [] () { return "hello user"; } );
\endcode
This path pattern creates a rule that forwards all requests with "/user"
to the provided hanlder, which in this case is a simple lambda (Note that
the handler syntax would look different when using QHttpServerRouterRule
directly, see below).
The path pattern can further contain a trailing "/" to create a rule that
addresses a collection of paths with arguments after the trailing "/". The
argument will be forwarded to the Rule as a \l QRegularExpressionMatch.
Using the QHttpServer::route convenience method the argument is directly
forwarded to the lambda:
\code
server.route("/user/", [] ( qint64 id ) { return "hello user"; } );
\endcode
This would match the request urls "/user/1", "/user/2" and so on.
The argument can be posititioned freely with the path pattern by using the
"<arg>" placeholder. This keyword further allows multiple placeholder.
\code
server.route("/user/<arg>/history", [] (qint64 id){ return "hello user"; } );
server.route("/user/<arg>/history/", [] (qint64 id, qint64 page){ return "hello user"; } );
\endcode
This would, for example, match the request url "/user/1/history/2".
All types which are registered in \l QHttpServerRouter::converters() can be
used in the callback and the respective placeholder.
\section1 Request Method
Request method is simply one of \l QHttpServerRequest::Method. If no
method is provided to any overload of the Rule construction, the rule will
match any request method.
\section1 Handler Signature
The handler is a callback with the signature
\code
void (*)(const QRegularExpressionMatch &, const QHttpServerRequest &, QHttpServerResponder &);
\endcode
The handler callback receives any matched placeholders as its first argument.
The second argument contains details about the request and the response has
to be written on the last argument by the handler.
The following code example shows how new rules with the respective handler can be created and
added to a \l QHttpServerRouter:
\code
template<typename ViewHandler>
void route(const char *path, const QHttpServerRequest::Methods methods, ViewHandler &&viewHandler)
{
auto rule = std::make_unique<QHttpServerRouterRule>(
path, methods, [this, viewHandler = std::forward<ViewHandler>(viewHandler)]
(QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QHttpServerResponder &&responder) mutable {
auto boundViewHandler = router.bindCaptured<ViewHandler>(
std::move(viewHandler), match);
(QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QHttpServerResponder &responder) mutable {
auto boundViewHandler = QHttpServerRouterRule::bindCaptured<ViewHandler>(
this, std::move(viewHandler), match);
// call viewHandler
boundViewHandler();
});
// QHttpServerRouter
router.addRule<ViewHandler>(std::move(rule));
// QHttpServerRouter
router.addRule<ViewHandler>(std::move(rule));
}
// Valid:
@ -61,40 +115,69 @@ Q_STATIC_LOGGING_CATEGORY(lcRouterRule, "qt.httpserver.router.rule")
//
route("/user/<arg>/history/", [] (qint64 id, qint64 page) { } ); // "/user/1/history/1"
// "/user/2/history/2"
// Invalid:
route("/user/<arg>", [] () { } ); // ERROR: path pattern has <arg>, but ViewHandler does not have any arguments
route("/user/\\d+", [] () { } ); // ERROR: path pattern does not support manual regexp
\endcode
\note This is a low level API, see \l QHttpServer for higher level alternatives.
\note Regular expressions in the path pattern are not supported, but
can be registered (to match a use of "<val>" to a specific type) using
QHttpServerRouter::addConverter().
can be registered (to match a use of "<arg>" to a specific type) using
\l QHttpServerRouter::addConverter().
*/
/*!
\typealias QHttpServerRouterRule::RouterHandler
/*! \fn template <typename Functor, typename ViewTraits = QHttpServerRouterViewTraits<Functor>> static typename ViewTraits::BindableType QHttpServerRouterRule::bindCaptured(QObject *receiver, Functor &&slot, const QRegularExpressionMatch &match) const
Type alias for
std::function<void(const QRegularExpressionMatch &,const QHttpServerRequest &, QHttpServerResponder &&)>
*/
Supplies the \a receiver and \a slot with arguments derived from a URL.
Returns the bound function that accepts whatever remaining arguments the
handler may take, supplying them to the slot after the URL-derived values.
Each match of the regex applied to the URL (as a string) is converted to
the type of the handler's parameter at its position, so that it can be
passed as \a match.
/*!
Constructs a rule with pathPattern \a pathPattern, and routerHandler \a routerHandler.
\code
QHttpServerRouter router;
The rule accepts all HTTP methods by default.
auto pageView = [] (const QString &page, const quint32 num) {
qDebug("page: %s, num: %d", qPrintable(page), num);
};
using ViewHandler = decltype(pageView);
\sa QHttpServerRequest::Methods
auto rule = std::make_unique<QHttpServerRouterRule>(
"/<arg>/<arg>/log",
[&router, &pageView] (QRegularExpressionMatch &match,
const QHttpServerRequest &request,
QHttpServerResponder &&responder) {
// Bind and call viewHandler with match's captured string and quint32:
QHttpServerRouterRule::bindCaptured(pageView, match)();
});
router.addRule<ViewHandler>(std::move(rule));
\endcode
*/
/*!
Constructs a rule with pathPattern \a pathPattern, methods \a methods
and routerHandler \a routerHandler.
/*! \fn template <typename Functor> QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern, const QHttpServerRequest::Methods methods, const QObject *receiver, Functor &&slot)
Constructs a rule for \a pathPattern, \a methods and connects it to \a
receiver and \a slot. The \a slot can also be a function pointer,
non-mutable lambda, or any other copiable callable with const call
operator. In that case the \a receiver will be a context object. The
handler will be valid until the receiver object is destroyed.
The rule accepts any combinations of available HTTP methods.
\sa QHttpServerRequest::Methods
*/
/*! \fn template <typename Functor> QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern, const QObject *receiver, Functor &&slot)
\overload
Constructs a rule for \a pathPattern, \l
QHttpServerRequest::Method::AnyKnown and connects it to \a receiver and \a
slot. The \a slot can also be a function pointer, non-mutable lambda, or
any other copiable callable with const call operator. In that case the \a
receiver will be a context object. The handler will be valid until the
receiver object is destroyed.
*/
QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
const QHttpServerRequest::Methods methods,
const QObject *context,
@ -107,7 +190,7 @@ QHttpServerRouterRule::QHttpServerRouterRule(const QString &pathPattern,
/*!
\internal
*/
*/
QHttpServerRouterRule::QHttpServerRouterRule(QHttpServerRouterRulePrivate *d)
: d_ptr(d)
{
@ -121,13 +204,15 @@ QHttpServerRouterRule::~QHttpServerRouterRule()
}
/*!
Returns the context object of this rule.
Returns the context object of this rule. This is the receiver that has to
handle the request.
*/
const QObject *QHttpServerRouterRule::contextObject() const
{
Q_D(const QHttpServerRouterRule);
return d->context;
}
/*!
Returns \c true if the methods is valid
*/
@ -138,9 +223,9 @@ bool QHttpServerRouterRule::hasValidMethods() const
}
/*!
Executes this rule for the given \a request, if it matches.
Executes this rule for the given \a request.
This function is called by QHttpServerRouter when it receives a new
This function is called by \l QHttpServerRouter when it receives a new
request. If the given \a request matches this rule, this function handles
the request by delivering a response to the given \a responder, then returns
\c true. Otherwise, it returns \c false.

View File

@ -40,6 +40,19 @@ private:
const QObject *context, QtPrivate::QSlotObjectBase *slotObjRaw);
public:
#ifdef Q_QDOC
template <typename Functor>
QHttpServerRouterRule(
const QString &pathPattern, const QHttpServerRequest::Methods methods,
const QObject *receiver,
Functor &&slot);
template <typename Functor>
QHttpServerRouterRule(
const QString &pathPattern,
const QObject *receiver,
Functor &&slot);
#else
template <typename Handler, if_routerhandler_prototype_compatible<Handler> = true>
QHttpServerRouterRule(
const QString &pathPattern,
@ -61,7 +74,15 @@ public:
QtPrivate::makeCallableObject<RouterHandlerPrototype>(std::forward<Handler>(func)))
{
}
#endif
#ifdef Q_QDOC
template <typename Functor, typename ViewTraits = QHttpServerRouterViewTraits<Functor>>
static typename ViewTraits::BindableType bindCaptured(
QObject *receiver,
Functor &&slot,
const QRegularExpressionMatch &match) const;
# else
template<typename ViewHandler, typename ViewTraits = QHttpServerRouterViewTraits<ViewHandler>>
static typename ViewTraits::BindableType bindCaptured(
const typename QtPrivate::ContextTypeForFunctor<ViewHandler>::ContextType *context,
@ -72,6 +93,7 @@ public:
context, std::forward<ViewHandler>(handler), match,
typename ViewTraits::Arguments::CapturableIndexes{});
}
#endif
const QObject *contextObject() const;