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 
13 using namespace Cutelyst;
14 
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 
69 ActionRESTPrivate::ActionRESTPrivate(ActionREST *q)
70  : q_ptr(q)
71 {
72 }
73 
74 bool 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 
113 bool 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 
123 bool 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 " +
131  response->setBody(body);
132  return true;
133 }
134 
135 QByteArray 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.
void clear()
int compare(QByteArrayView bv, Qt::CaseSensitivity cs) const const
void append(QList::parameter_type value)
qsizetype removeAll(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