5 #include "actionchain.h" 8 #include "dispatchtypechained_p.h" 11 #include <QtCore/QUrl> 17 , d_ptr(new DispatchTypeChainedPrivate)
21 DispatchTypeChained::~DispatchTypeChained()
31 Actions endPoints = d->endPoints;
32 std::sort(endPoints.begin(), endPoints.end(), [](
Action *a,
Action *b) ->
bool {
33 return a->
reverse() < b->reverse();
38 for (
Action *endPoint : endPoints) {
40 if (endPoint->numberOfArgs() == -1) {
43 for (
int i = 0; i < endPoint->numberOfArgs(); ++i) {
49 QString extra = DispatchTypeChainedPrivate::listExtraHttpMethods(endPoint);
50 QString consumes = DispatchTypeChainedPrivate::listExtraConsumes(endPoint);
52 Action *current = endPoint;
60 for (
const QString &part : pathParts) {
61 if (!part.isEmpty()) {
67 current = d->actions.value(
parent);
73 if (
parent.compare(u
"/") != 0) {
81 unattachedTable.
append(row);
86 for (
Action *p : parents) {
89 QString extraHttpMethod = DispatchTypeChainedPrivate::listExtraHttpMethods(p);
90 if (!extraHttpMethod.
isEmpty()) {
94 const auto attributes = p->attributes();
96 if (it != attributes.constEnd()) {
102 QString ct = DispatchTypeChainedPrivate::listExtraConsumes(p);
107 if (p != parents[0]) {
122 if (endPoint->numberOfArgs() == -1) {
138 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 144 if (!paths.isEmpty()) {
145 out << Utils::buildTable(paths,
150 if (!unattachedTable.
isEmpty()) {
151 out << Utils::buildTable(unattachedTable,
168 const BestActionMatch ret =
171 if (ret.isNull || chain.
isEmpty()) {
177 for (
const QString &arg : parts) {
179 decodedArgs.
append(Utils::decodePercentEncoding(&aux));
183 Request *request = c->request();
202 if (chainedList.
size() > 1) {
203 qCCritical(CUTELYST_DISPATCHER_CHAINED)
204 <<
"Multiple Chained attributes not supported registering" << action->
reverse();
209 if (chainedTo == u
'/' + action->
name()) {
210 qCCritical(CUTELYST_DISPATCHER_CHAINED)
211 <<
"Actions cannot chain to themselves registering /" << action->
name();
219 if (pathPart.
size() == 1 && !pathPart[0].
isEmpty()) {
221 }
else if (pathPart.
size() > 1) {
222 qCCritical(CUTELYST_DISPATCHER_CHAINED)
223 <<
"Multiple PathPart attributes not supported registering" << action->
reverse();
228 qCCritical(CUTELYST_DISPATCHER_CHAINED)
229 <<
"Absolute parameters to PathPart not allowed registering" << action->
reverse();
233 attributes.
replace(QStringLiteral(
"PathPart"), part);
236 auto &childrenOf = d->childrenOf[chainedTo][part];
237 childrenOf.insert(childrenOf.begin(), action);
248 qCCritical(CUTELYST_DISPATCHER_CHAINED)
249 <<
"Combining Args and CaptureArgs attributes not supported registering" 267 if (!(attributes.
contains(QStringLiteral(
"Chained")) &&
268 !attributes.
contains(QStringLiteral(
"CaptureArgs")))) {
269 qCWarning(CUTELYST_DISPATCHER_CHAINED)
270 <<
"uriForAction: action is not an end point" << action;
280 if (curr_attributes.
contains(QStringLiteral(
"CaptureArgs"))) {
283 qCWarning(CUTELYST_DISPATCHER_CHAINED)
293 const QString pp = curr_attributes.
value(QStringLiteral(
"PathPart"));
298 parent = curr_attributes.
value(QStringLiteral(
"Chained"));
299 curr = d->actions.value(
parent);
302 if (
parent.compare(u
"/") != 0) {
304 qCWarning(CUTELYST_DISPATCHER_CHAINED) <<
"uriForAction: dangling action" <<
parent;
308 if (!localCaptures.
isEmpty()) {
310 qCWarning(CUTELYST_DISPATCHER_CHAINED)
311 <<
"uriForAction: too many captures" << localCaptures;
324 if (qobject_cast<ActionChain *>(action)) {
339 curr = d->actions.value(
parent);
342 return new ActionChain(chain, const_cast<Context *>(c));
349 if (d->actions.isEmpty()) {
358 BestActionMatch DispatchTypeChainedPrivate::recurseMatch(
int reqArgsSize,
362 BestActionMatch bestAction;
363 auto it = childrenOf.constFind(parent);
364 if (it == childrenOf.constEnd()) {
368 const StringActionsMap &children = it.value();
372 return b.size() < a.
size();
375 for (
const QString &tryPart : keys) {
377 if (!tryPart.isEmpty()) {
385 parts = parts.
mid(tryPartCount);
388 const Actions tryActions = children.value(tryPart);
389 for (
Action *action : tryActions) {
391 if (attributes.
contains(QStringLiteral(
"CaptureArgs"))) {
392 const int captureCount = action->numberOfCaptures();
394 if (parts.
size() < captureCount) {
402 if (!action->matchCaptures(captures.
size())) {
409 const BestActionMatch ret =
410 recurseMatch(reqArgsSize,
QLatin1Char(
'/') + action->reverse(), localParts);
418 int bestActionParts = bestAction.parts.
size();
420 if (!actions.isEmpty() &&
421 (bestAction.isNull || actionParts.
size() < bestActionParts ||
422 (actionParts.
size() == bestActionParts &&
423 actionCaptures.
size() < bestAction.captures.size() &&
424 ret.n_pathParts > bestAction.n_pathParts))) {
425 actions.prepend(action);
428 bestAction.actions = actions;
429 bestAction.captures = captures + actionCaptures;
430 bestAction.parts = actionParts;
431 bestAction.n_pathParts = pathparts + ret.n_pathParts;
432 bestAction.isNull =
false;
435 if (!action->match(reqArgsSize + parts.
size())) {
439 const QString argsAttr = attributes.
value(QStringLiteral(
"Args"));
440 const int pathparts =
449 if (bestAction.isNull || parts.
size() < bestAction.parts.size() ||
450 (parts.
isEmpty() && !argsAttr.
isEmpty() && action->numberOfArgs() == 0)) {
451 bestAction.actions = {action};
453 bestAction.parts = parts;
454 bestAction.n_pathParts = pathparts;
455 bestAction.isNull =
false;
464 bool DispatchTypeChainedPrivate::checkArgsAttr(
Action *action,
const QString &name)
const 472 if (values.
size() > 1) {
473 qCCritical(CUTELYST_DISPATCHER_CHAINED)
474 <<
"Multiple" << name <<
"attributes not supported registering" << action->
reverse();
481 qCCritical(CUTELYST_DISPATCHER_CHAINED)
482 <<
"Invalid" << name <<
"(" << args <<
") for action" << action->
reverse() <<
"(use '" 483 << name <<
"' or '" << name <<
"(<number>)')";
490 QString DispatchTypeChainedPrivate::listExtraHttpMethods(
Action *action)
501 QString DispatchTypeChainedPrivate::listExtraConsumes(
Action *action)
512 #include "moc_dispatchtypechained.cpp" ParamsMultiMap attributes() const noexcept
Action * expandAction(const Context *c, Action *action) const final
QString & append(QChar ch)
virtual bool inUse() override
virtual bool registerAction(Action *action) override
registerAction
void append(const T &value)
QString & prepend(QChar ch)
Holds a chain of Cutelyst Actions.
void setupMatchedAction(Context *c, Action *action) const
QString join(const QString &separator) const const
void setMatch(const QString &match)
This class represents a Cutelyst Action.
QString number(int n, int base)
int count(const T &value) const const
void append(const T &value)
DispatchTypeChained(QObject *parent=nullptr)
void setAttributes(const ParamsMultiMap &attributes)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
virtual qint8 numberOfCaptures() const noexcept
The Cutelyst namespace holds all public Cutelyst API.
virtual MatchType match(Context *c, const QString &path, const QStringList &args) const override
void setCaptures(const QStringList &captures)
virtual QString uriForAction(Action *action, const QStringList &captures) const override
void setArguments(const QStringList &arguments)
bool contains(const Key &key, const T &value) const const
QString & replace(int position, int n, QChar after)
bool isEmpty() const const
QList< T > mid(int pos, int length) const const
void prepend(const T &value)
virtual QByteArray list() const override
list the registered actions To be implemented by subclasses
QString attribute(const QString &name, const QString &defaultValue={}) const
QObject * parent() const const
QList< T > values(const Key &key) const const
const T value(const Key &key, const T &defaultValue) const const