cutelyst  4.5.1
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 using 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 
70 ActionRESTPrivate::ActionRESTPrivate(ActionREST *q)
71  : q_ptr(q)
72 {
73 }
74 
75 bool 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"_qba);
103  } else if (httpMethod.compare("not_implemented") != 0) {
104  // try dispatching to foo_not_implemented
105  ret = dispatchRestMethod(c, "not_implemented"_qba);
106  } else {
107  // not_implemented
108  ret = returnNotImplemented(c, q->name());
109  }
110 
111  return ret;
112 }
113 
114 bool ActionRESTPrivate::returnOptions(Context *c, const QString &methodName) const
115 {
116  Response *response = c->response();
117  response->setContentType("text/plain"_qba);
118  response->setStatus(Response::OK); // 200
119  response->setHeader("Allow"_qba, getAllowedMethods(c->controller(), methodName));
120  response->body().clear();
121  return true;
122 }
123 
124 bool ActionRESTPrivate::returnNotImplemented(Context *c, const QString &methodName) const
125 {
126  Response *response = c->response();
127  response->setStatus(Response::MethodNotAllowed); // 405
128  response->setHeader("Allow"_qba, 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 
136 QByteArray 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
Definition: actionrest.cpp:59
ActionREST(QObject *parent=nullptr)
Definition: actionrest.cpp:54
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)
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