cutelyst 4.8.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-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "actionrest_p.h"
6#include "context.h"
7#include "controller.h"
8#include "dispatcher.h"
9
10#include <QDebug>
11#include <QUrl>
12
13using namespace Cutelyst;
14using namespace Qt::StringLiterals;
15
55 : Action(new ActionRESTPrivate(this), parent)
56{
57}
58
60{
61 Q_D(const ActionREST);
62
63 if (!Action::doExecute(c)) {
64 return false;
65 }
66
67 return d->dispatchRestMethod(c, c->request()->method());
68}
69
70ActionRESTPrivate::ActionRESTPrivate(ActionREST *q)
71 : q_ptr(q)
72{
73}
74
75bool ActionRESTPrivate::dispatchRestMethod(Context *c, const QByteArray &httpMethod) const
76{
77 Q_Q(const ActionREST);
78 const QString restMethod = q->name() + u'_' + QString::fromLatin1(httpMethod);
79
80 Controller *controller = q->controller();
81 Action *action = controller->actionFor(restMethod);
82 if (!action) {
83 // Look for non registered actions in this controller
84 const ActionList actions = controller->actions();
85 for (Action *controllerAction : actions) {
86 if (controllerAction->name() == restMethod) {
87 action = controllerAction;
88 break;
89 }
90 }
91 }
92
93 if (action) {
94 return c->execute(action);
95 }
96
97 bool ret = false;
98 if (httpMethod.compare("OPTIONS") == 0) {
99 ret = returnOptions(c, q->name());
100 } else if (httpMethod.compare("HEAD") == 0) {
101 // redispatch to GET
102 ret = dispatchRestMethod(c, "GET"_ba);
103 } else if (httpMethod.compare("not_implemented") != 0) {
104 // try dispatching to foo_not_implemented
105 ret = dispatchRestMethod(c, "not_implemented"_ba);
106 } else {
107 // not_implemented
108 ret = returnNotImplemented(c, q->name());
109 }
110
111 return ret;
112}
113
114bool ActionRESTPrivate::returnOptions(Context *c, const QString &methodName) const
115{
116 Response *response = c->response();
117 response->setContentType("text/plain"_ba);
118 response->setStatus(Response::OK); // 200
119 response->setHeader("Allow"_ba, getAllowedMethods(c->controller(), methodName));
120 response->body().clear();
121 return true;
122}
123
124bool ActionRESTPrivate::returnNotImplemented(Context *c, const QString &methodName) const
125{
126 Response *response = c->response();
127 response->setStatus(Response::MethodNotAllowed); // 405
128 response->setHeader("Allow"_ba, getAllowedMethods(c->controller(), methodName));
129
130 const QByteArray body = "Method " + c->req()->method() + " not implemented for " +
132 response->setBody(body);
133 return true;
134}
135
136QByteArray Cutelyst::ActionRESTPrivate::getAllowedMethods(Controller *controller,
137 const QString &methodName) const
138{
139 QStringList methods;
140 const QString name = methodName + u'_';
141 const ActionList actions = controller->actions();
142 for (Action *action : actions) {
143 const QString method = action->name();
144 if (method.startsWith(name)) {
145 methods.append(method.mid(name.size()));
146 }
147 }
148
149 if (methods.contains(u"GET")) {
150 methods.append(QStringLiteral("HEAD"));
151 }
152
153 methods.removeDuplicates();
154 methods.removeOne(u"not_implemented"_s);
155 methods.sort();
156
157 return methods.join(u", ").toLatin1();
158}
159
160#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
Action(QObject *parent=nullptr)
Definition action.cpp:13
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:238
void setStatus(quint16 status) noexcept
Definition response.cpp:73
void setBody(QIODevice *body)
Definition response.cpp:104
void setHeader(const QByteArray &key, const QByteArray &value)
Definition response.cpp:283
QByteArray & body()
Definition response.cpp:86
The Cutelyst namespace holds all public Cutelyst API.
QVector< Action * > ActionList
Definition action.h:161
void clear()
int compare(QByteArrayView bv, Qt::CaseSensitivity cs) const const
void append(QList< T > &&value)
bool removeOne(const AT &t)
QObject(QObject *parent)
QObject * parent() const const
QString fromLatin1(QByteArrayView str)
QString mid(qsizetype position, qsizetype n) &&
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