cutelyst 4.4.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;
14
53ActionREST::ActionREST(QObject *parent)
54 : Action(new ActionRESTPrivate(this), parent)
55{
56}
57
59{
60 Q_D(const ActionREST);
61
62 if (!Action::doExecute(c)) {
63 return false;
64 }
65
66 return d->dispatchRestMethod(c, c->request()->method());
67}
68
69ActionRESTPrivate::ActionRESTPrivate(ActionREST *q)
70 : q_ptr(q)
71{
72}
73
74bool ActionRESTPrivate::dispatchRestMethod(Context *c, const QByteArray &httpMethod) const
75{
76 Q_Q(const ActionREST);
77 const QString restMethod = q->name() + u'_' + QString::fromLatin1(httpMethod);
78
79 Controller *controller = q->controller();
80 Action *action = controller->actionFor(restMethod);
81 if (!action) {
82 // Look for non registered actions in this controller
83 const ActionList actions = controller->actions();
84 for (Action *controllerAction : actions) {
85 if (controllerAction->name() == restMethod) {
86 action = controllerAction;
87 break;
88 }
89 }
90 }
91
92 if (action) {
93 return c->execute(action);
94 }
95
96 bool ret = false;
97 if (httpMethod.compare("OPTIONS") == 0) {
98 ret = returnOptions(c, q->name());
99 } else if (httpMethod.compare("HEAD") == 0) {
100 // redispatch to GET
101 ret = dispatchRestMethod(c, "GET"_qba);
102 } else if (httpMethod.compare("not_implemented") != 0) {
103 // try dispatching to foo_not_implemented
104 ret = dispatchRestMethod(c, "not_implemented"_qba);
105 } else {
106 // not_implemented
107 ret = returnNotImplemented(c, q->name());
108 }
109
110 return ret;
111}
112
113bool ActionRESTPrivate::returnOptions(Context *c, const QString &methodName) const
114{
115 Response *response = c->response();
116 response->setContentType("text/plain"_qba);
117 response->setStatus(Response::OK); // 200
118 response->setHeader("Allow"_qba, getAllowedMethods(c->controller(), methodName));
119 response->body().clear();
120 return true;
121}
122
123bool ActionRESTPrivate::returnNotImplemented(Context *c, const QString &methodName) const
124{
125 Response *response = c->response();
126 response->setStatus(Response::MethodNotAllowed); // 405
127 response->setHeader("Allow"_qba, getAllowedMethods(c->controller(), methodName));
128
129 const QByteArray body = "Method " + c->req()->method() + " not implemented for " +
130 c->request()->uri().toString(QUrl::FullyEncoded).toLatin1();
131 response->setBody(body);
132 return true;
133}
134
135QByteArray Cutelyst::ActionRESTPrivate::getAllowedMethods(Controller *controller,
136 const QString &methodName) const
137{
138 QStringList methods;
139 const QString name = methodName + u'_';
140 const ActionList actions = controller->actions();
141 for (Action *action : actions) {
142 const QString method = action->name();
143 if (method.startsWith(name)) {
144 methods.append(method.mid(name.size()));
145 }
146 }
147
148 if (methods.contains(u"GET")) {
149 methods.append(QStringLiteral("HEAD"));
150 }
151
152 methods.removeAll(QStringLiteral("not_implemented"));
153 methods.sort();
154 methods.removeDuplicates();
155
156 return methods.join(u", ").toLatin1();
157}
158
159#include "moc_actionrest.cpp"
Automated REST method dispatching.
Definition: actionrest.h:15
bool doExecute(Context *c) override
Definition: actionrest.cpp:58
ActionREST(QObject *parent=nullptr)
Definition: actionrest.cpp:53
This class represents a Cutelyst Action.
Definition: action.h:35
bool doExecute(Context *c) override
Definition: action.cpp:136
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:423
Response * response() const noexcept
Definition: context.cpp:97
Cutelyst Controller base class.
Definition: controller.h:56
ActionList actions() const noexcept
Definition: controller.cpp:269
Action * actionFor(QStringView name) const
Definition: controller.cpp:259
A Cutelyst response.
Definition: response.h:29
void setContentType(const QByteArray &type)
Definition: response.h:238
void setStatus(quint16 status) noexcept
Definition: response.cpp:72
void setHeader(const QByteArray &key, const QByteArray &value)
void setBody(QIODevice *body)
Definition: response.cpp:103
QByteArray & body()
Definition: response.cpp:85
The Cutelyst namespace holds all public Cutelyst API.
QVector< Action * > ActionList
Definition: action.h:161