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