5#include "actionchain.h" 
    8#include "dispatchtypechained_p.h" 
   17    , d_ptr(new DispatchTypeChainedPrivate)
 
 
   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) {
 
  141        out << Utils::buildTable(paths,
 
  146    if (!unattachedTable.
isEmpty()) {
 
  147        out << Utils::buildTable(unattachedTable,
 
 
  166    const BestActionMatch ret =
 
  169    if (ret.isNull || chain.
isEmpty()) {
 
  175    for (
const QString &arg : parts) {
 
  177        decodedArgs.
append(Utils::decodePercentEncoding(&aux));
 
 
  200    if (chainedList.
size() > 1) {
 
  201        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  202            << 
"Multiple Chained attributes not supported registering" << action->
reverse();
 
  207    if (chainedTo == u
'/' + action->
name()) {
 
  208        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  209            << 
"Actions cannot chain to themselves registering /" << action->
name();
 
  217    if (pathPart.
size() == 1 && !pathPart[0].
isEmpty()) {
 
  219    } 
else if (pathPart.
size() > 1) {
 
  220        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  221            << 
"Multiple PathPart attributes not supported registering" << action->
reverse();
 
  226        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  227            << 
"Absolute parameters to PathPart not allowed registering" << action->
reverse();
 
  231    attributes.
replace(QStringLiteral(
"PathPart"), part);
 
  234    auto &childrenOf = d->childrenOf[chainedTo][part];
 
  235    childrenOf.insert(childrenOf.begin(), action);
 
  246        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  247            << 
"Combining Args and CaptureArgs attributes not supported registering" 
 
  265    if (!(attributes.
contains(QStringLiteral(
"Chained")) &&
 
  266          !attributes.
contains(QStringLiteral(
"CaptureArgs")))) {
 
  267        qCWarning(CUTELYST_DISPATCHER_CHAINED)
 
  268            << 
"uriForAction: action is not an end point" << action;
 
  278        if (curr_attributes.
contains(QStringLiteral(
"CaptureArgs"))) {
 
  281                qCWarning(CUTELYST_DISPATCHER_CHAINED)
 
  291        const QString pp = curr_attributes.
value(QStringLiteral(
"PathPart"));
 
  296        parent = curr_attributes.
value(QStringLiteral(
"Chained"));
 
  297        curr   = d->actions.value(
parent);
 
  300    if (
parent.compare(u
"/") != 0) {
 
  302        qCWarning(CUTELYST_DISPATCHER_CHAINED) << 
"uriForAction: dangling action" << 
parent;
 
  306    if (!localCaptures.
isEmpty()) {
 
  308        qCWarning(CUTELYST_DISPATCHER_CHAINED)
 
  309            << 
"uriForAction: too many captures" << localCaptures;
 
 
  322    if (qobject_cast<ActionChain *>(action)) {
 
  337        curr                 = d->actions.value(
parent);
 
 
  347    if (d->actions.isEmpty()) {
 
 
  356BestActionMatch DispatchTypeChainedPrivate::recurseMatch(
int reqArgsSize,
 
  360    BestActionMatch bestAction;
 
  361    auto it = childrenOf.constFind(parent);
 
  362    if (it == childrenOf.constEnd()) {
 
  366    const StringActionsMap &children = it.value();
 
  370        return b.size() < a.size();
 
  373    for (
const QString &tryPart : keys) {
 
  375        if (!tryPart.isEmpty()) {
 
  383            parts = parts.
mid(tryPartCount);
 
  386        const Actions tryActions = children.value(tryPart);
 
  387        for (
Action *action : tryActions) {
 
  389            if (attributes.
contains(QStringLiteral(
"CaptureArgs"))) {
 
  390                const int captureCount = action->numberOfCaptures();
 
  392                if (parts.
size() < captureCount) {
 
  400                if (!action->matchCaptures(captures.
size())) {
 
  407                const BestActionMatch ret =
 
  408                    recurseMatch(reqArgsSize, 
QLatin1Char(
'/') + action->reverse(), localParts);
 
  416                int bestActionParts              = bestAction.parts.
size();
 
  419                    (bestAction.isNull || actionParts.
size() < bestActionParts ||
 
  420                     (actionParts.
size() == bestActionParts &&
 
  421                      actionCaptures.
size() < bestAction.captures.size() &&
 
  422                      ret.n_pathParts > bestAction.n_pathParts))) {
 
  426                    bestAction.actions     = actions;
 
  427                    bestAction.captures    = captures + actionCaptures;
 
  428                    bestAction.parts       = actionParts;
 
  429                    bestAction.n_pathParts = pathparts + ret.n_pathParts;
 
  430                    bestAction.isNull      = 
false;
 
  433                if (!action->match(reqArgsSize + parts.
size())) {
 
  437                const QString argsAttr = attributes.
value(QStringLiteral(
"Args"));
 
  438                const int pathparts =
 
  447                if (bestAction.isNull || parts.
size() < bestAction.parts.size() ||
 
  448                    (parts.
isEmpty() && !argsAttr.
isEmpty() && action->numberOfArgs() == 0)) {
 
  449                    bestAction.actions     = {action};
 
  451                    bestAction.parts       = parts;
 
  452                    bestAction.n_pathParts = pathparts;
 
  453                    bestAction.isNull      = 
false;
 
  462bool DispatchTypeChainedPrivate::checkArgsAttr(
Action *action, 
const QString &name)
 const 
  470    if (values.
size() > 1) {
 
  471        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  472            << 
"Multiple" << name << 
"attributes not supported registering" << action->
reverse();
 
  479        qCCritical(CUTELYST_DISPATCHER_CHAINED)
 
  480            << 
"Invalid" << name << 
"(" << args << 
") for action" << action->
reverse() << 
"(use '" 
  481            << name << 
"' or '" << name << 
"(<number>)')";
 
  488QString DispatchTypeChainedPrivate::listExtraHttpMethods(
Action *action)
 
  499QString DispatchTypeChainedPrivate::listExtraConsumes(
Action *action)
 
  510#include "moc_dispatchtypechained.cpp" 
Holds a chain of Cutelyst actions.
This class represents a Cutelyst Action.
void setAttributes(const ParamsMultiMap &attributes)
virtual qint8 numberOfCaptures() const
ParamsMultiMap attributes() const noexcept
QString attribute(const QString &name, const QString &defaultValue={}) const
QString reverse() const noexcept
QString name() const noexcept
Describes a chained dispatch type.
MatchType match(Context *c, QStringView path, const QStringList &args) const override
QString uriForAction(Action *action, const QStringList &captures) const override
QByteArray list() const override
bool registerAction(Action *action) override
Action * expandAction(const Context *c, Action *action) const final
~DispatchTypeChained() override
DispatchTypeChained(QObject *parent=nullptr)
Abstract class to described a dispatch type.
void setupMatchedAction(Context *c, Action *action) const
void setCaptures(const QStringList &captures)
void setArguments(const QStringList &arguments)
void setMatch(const QString &match)
The Cutelyst namespace holds all public Cutelyst API.
void append(QList::parameter_type value)
qsizetype count() const const
bool isEmpty() const const
QList< T > mid(qsizetype pos, qsizetype length) const const
void prepend(QList::parameter_type value)
qsizetype size() const const
bool contains(const Key &key) const const
T value(const Key &key, const T &defaultValue) const const
QList< T > values() const const
QObject * parent() const const
QString & append(QChar ch)
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & prepend(QChar ch)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QString join(QChar separator) const const
QStringView mid(qsizetype start, qsizetype length) const const
QString toString() const const