cutelyst 5.0.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
actionrest.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2013-2025 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "actionrest_p.h"
6#include "context.h"
7#include "context_p.h"
8#include "controller.h"
9#include "dispatcher.h"
10
11#include <QDebug>
12#include <QUrl>
13
14using namespace Cutelyst;
15using namespace Qt::StringLiterals;
16
56 : Action(new ActionRESTPrivate(this), parent)
57{
58}
59
61{
62 Q_D(const ActionREST);
63
64 int &actionRefCount = c->d_ptr->actionRefCount;
65
66 if (!Action::doExecute(c)) {
67 return false;
68 }
69
70 Action *action = d->getRestAction(c, c->request()->method());
71 if (action) {
72 if (actionRefCount) {
73 // Async
74 c->d_ptr->pendingAsync.enqueue(action);
75 return true;
76 } else {
77 return c->execute(action);
78 }
79 }
80
81 return true;
82}
83
84ActionRESTPrivate::ActionRESTPrivate(ActionREST *q)
85 : q_ptr(q)
86{
87}
88
89Action *ActionRESTPrivate::getRestAction(Context *c, const QByteArray &httpMethod) const
90{
91 Q_Q(const ActionREST);
92 const QString restMethod = q->name() + u'_' + QString::fromLatin1(httpMethod);
93
94 Controller *controller = q->controller();
95 Action *action = controller->actionFor(restMethod);
96 if (!action) {
97 // Look for non registered actions in this controller
98 const ActionList actions = controller->actions();
99 for (Action *controllerAction : actions) {
100 if (controllerAction->name() == restMethod) {
101 action = controllerAction;
102 break;
103 }
104 }
105 }
106
107 if (!action) {
108 if (httpMethod == "HEAD") {
109 // redispatch to GET
110 action = getRestAction(c, "GET"_ba);
111 } else if (httpMethod == "OPTIONS") {
112 returnOptions(c, q->name());
113 } else if (httpMethod == "not_implemented") {
114 // not_implemented
115 returnNotImplemented(c, q->name());
116 } else {
117 // try dispatching to foo_not_implemented
118 action = getRestAction(c, "not_implemented"_ba);
119 }
120 }
121
122 return action;
123}
124
125void ActionRESTPrivate::returnOptions(Context *c, const QString &methodName) const
126{
127 Response *response = c->response();
128 response->setContentType("text/plain"_ba);
129 response->setStatus(Response::OK); // 200
130 response->setHeader("Allow", getAllowedMethods(c->controller(), methodName));
131 response->body().clear();
132}
133
134void ActionRESTPrivate::returnNotImplemented(Context *c, const QString &methodName) const
135{
136 Response *response = c->response();
137 response->setStatus(Response::MethodNotAllowed); // 405
138 response->setHeader("Allow", getAllowedMethods(c->controller(), methodName));
139
140 const QByteArray body = "Method " + c->req()->method() + " not implemented for " +
142 response->setBody(body);
143}
144
145QByteArray Cutelyst::ActionRESTPrivate::getAllowedMethods(Controller *controller,
146 const QString &methodName) const
147{
148 QStringList methods;
149 const QString name = methodName + u'_';
150 const ActionList actions = controller->actions();
151 for (Action *action : actions) {
152 const QString method = action->name();
153 if (method.startsWith(name)) {
154 methods.append(method.mid(name.size()));
155 }
156 }
157
158 if (methods.contains(u"GET")) {
159 methods.append(QStringLiteral("HEAD"));
160 }
161
162 methods.removeDuplicates();
163 methods.removeOne(u"not_implemented"_s);
164 methods.sort();
165
166 return methods.join(u", ").toLatin1();
167}
168
169#include "moc_actionrest.cpp"
Automated REST method dispatching.
Definition actionrest.h:15
bool doExecute(Context *c) override
ActionREST(QObject *parent=nullptr)
This class represents a Cutelyst Action.
Definition action.h:35
bool doExecute(Context *c) override
Definition action.cpp:137
QString name() const noexcept
Definition component.cpp:33
The Cutelyst Context.
Definition context.h:42
Request * request
Definition context.h:71
Request * req
Definition context.h:66
Controller * controller
Definition context.h:75
bool execute(Component *code)
Definition context.cpp:424
Response * response() const noexcept
Definition context.cpp:98
Cutelyst Controller base class.
Definition controller.h:56
ActionList actions() const noexcept
Action * actionFor(QStringView name) const
A Cutelyst response.
Definition response.h:29
void setContentType(const QByteArray &type)
Definition response.h:230
void setStatus(quint16 status) noexcept
Definition response.cpp:74
void setHeader(const QByteArray &key, const QByteArray &value)
void setBody(QIODevice *body)
Definition response.cpp:105
QByteArray & body()
Definition response.cpp:87
The Cutelyst namespace holds all public Cutelyst API.
void clear()
void append(QList::parameter_type value)
bool removeOne(const AT &t)
QString fromLatin1(QByteArrayView str)
QString mid(qsizetype position, qsizetype n) const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
qsizetype removeDuplicates()
void sort(Qt::CaseSensitivity cs)
FullyEncoded
QString toString(QUrl::FormattingOptions options) const const