request.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. Copyright 2017 Herik Lima de Castro and Marcelo Medeiros Eler
  3. Distributed under MIT license, or public domain if desired and
  4. recognized in your jurisdiction.
  5. See file LICENSE for detail.
  6. */
  7. #ifndef Request_H
  8. #define Request_H
  9. #include <QThread>
  10. #include <QTcpSocket>
  11. #include <QJsonArray>
  12. #include <QJsonObject>
  13. #include <QJsonDocument>
  14. #include "httpparser.h"
  15. #include "session.h"
  16. #include "configuration.h"
  17. #include "requestdispatcher.h"
  18. #include "cppwebframework_global.h"
  19. CWF_BEGIN_NAMESPACE
  20. /**
  21. * @brief The Request class holds all information about a http request.
  22. */
  23. class CPPWEBFRAMEWORKSHARED_EXPORT Request
  24. {
  25. friend class HttpReadRequest;
  26. friend class RequestDispatcher;
  27. QTcpSocket &socket;
  28. Session *session = nullptr;
  29. HttpParser *httpParser = nullptr;
  30. RequestDispatcher *requestDispatcher = nullptr;
  31. Response *response = nullptr;
  32. QMap<QString, QObject *> attributes;
  33. QMapThreadSafety<QString, Session *> &sessions;
  34. const Configuration &configuration;
  35. public:
  36. /**
  37. * @brief This constructor needs to receive a reference to a QTcpSocket and QByteArray.
  38. * The parameter parent is optional.
  39. * NOTE: The CppWebServer is responsable to create the QTcpSocket, and the HttpReadRequest is
  40. * responsable to create a HttpReadRequest and a Response.
  41. */
  42. explicit Request(QTcpSocket &socket, QMapThreadSafety<QString, Session *> &sessions, const Configuration &configuration);
  43. /**
  44. * @brief Destroys dynamically allocated resources.
  45. */
  46. ~Request() noexcept;
  47. /**
  48. * @brief This method add attributes that will be passed to a view page.
  49. * The object can be processed within a page using view CSTL. For this to be possible the object must
  50. * inherit from QObject and methods and must be in session "public slots".
  51. */
  52. inline void addAttribute(const std::initializer_list<QPair<QString, QObject *>> &value) noexcept
  53. {
  54. std::for_each(value.begin(), value.end(), [&](const QPair<QString, QObject *> &v){attributes.insert(v.first, v.second);});
  55. }
  56. /**
  57. * @brief This method add an attribute that will be passed to a view page.
  58. * The object can be processed within a page using view CSTL. For this to be possible the object must
  59. * inherit from QObject and methods and must be in session "public slots".
  60. */
  61. inline void addAttribute(const QString &name, QObject *value) noexcept { attributes.insert(name, value); }
  62. /**
  63. * @brief This method returns all the attributes of a HttpReadRequest.
  64. */
  65. inline QMap<QString, QObject *> getAttributes() const noexcept { return attributes; }
  66. /**
  67. * @brief This method returns a specific object given its name.
  68. */
  69. inline const QObject *getAttribute(const QString &name) const noexcept { return attributes.contains(name) ? attributes[name] : nullptr; }
  70. /**
  71. * @brief Returns the request body.
  72. */
  73. inline const QByteArray getBody() const noexcept { return httpParser->getBody(); }
  74. /**
  75. * @brief Tries returns the body of the converted request to QJsonObject.
  76. */
  77. inline QJsonObject bodyToJsonObject() const noexcept { return QJsonDocument::fromJson(httpParser->getBody()).object(); }
  78. /**
  79. * @brief Tries returns the body of the converted request to QJsonArray.
  80. */
  81. inline QJsonArray bodyToJsonArray() const noexcept { return QJsonDocument::fromJson(httpParser->getBody()).array(); }
  82. /**
  83. * @brief This method returns a requestDispatcher given an specific page.
  84. * @param page : This is a reference to a QByteArray.
  85. * @return RequestDispatcher
  86. */
  87. RequestDispatcher &getRequestDispatcher(const QString &page);
  88. /**
  89. * @brief This method returns the http protocol.
  90. * @return QByteArray
  91. */
  92. inline QByteArray getProtocol() const noexcept { return httpParser != nullptr ? httpParser->getHttpVersion() : ""; }
  93. /**
  94. * @brief This method will clear all the attributes.
  95. */
  96. inline void clearAttributes() noexcept { attributes.clear(); }
  97. /**
  98. * @brief This method set the HttpParser.
  99. * @param httpParser
  100. */
  101. inline void setHttpParser(HttpParser &httpParser) noexcept { this->httpParser = &httpParser; }
  102. /**
  103. * @brief This method returns the HttpParser.
  104. * @return HttpParser
  105. */
  106. inline HttpParser &getHttpParser() const noexcept { return *httpParser; }
  107. /**
  108. * @brief This method returns the requested url.
  109. * @return QByteArray
  110. */
  111. inline QByteArray getRequestURL() const noexcept{ return httpParser != nullptr ? httpParser->getUrl() : ""; }
  112. /**
  113. * @brief This method returns the requested url.
  114. * @return QByteArray
  115. */
  116. inline QByteArray getRequestURI() const noexcept { return httpParser != nullptr ? httpParser->getUrl() : ""; }
  117. /**
  118. * @brief This method returns the user's session.
  119. */
  120. Session &getSession();
  121. /**
  122. * @brief This method set the user's session.
  123. * @return Session
  124. */
  125. inline void setSession(Session &session) noexcept { this->session = &session; }
  126. /**
  127. * @brief This method returns the most recent parameter from a request given an specific name.
  128. * @param name : This is a reference to a QByteArray.
  129. * @param decode : If true, decode the parameter.
  130. * @return QByteArray
  131. */
  132. QByteArray getParameter(const QByteArray &name, bool urlDecode = true, bool replacePlusForSpace = true) const noexcept
  133. {
  134. return httpParser->getParameter(name, urlDecode, replacePlusForSpace);
  135. }
  136. /**
  137. * @brief This method returns the parameters from a request given an specific name.
  138. * @param name : This is a reference to a QByteArray.
  139. * @return QByteArray
  140. */
  141. inline QByteArrayList getParameters(const QByteArray &name) const noexcept { return httpParser->getParameters(name); }
  142. /**
  143. * @brief This method returns a reference to the current socket.
  144. * @return QTcpSocket
  145. */
  146. inline QTcpSocket &getSocket() const noexcept { return socket; }
  147. /**
  148. * @brief This method returns the path.
  149. * @return QString
  150. */
  151. inline QString getPath() const noexcept { return configuration.getPath(); }
  152. /**
  153. * @brief This method returns all the files that the user has sent.
  154. * @return QMap<QByteArray, QByteArray>
  155. */
  156. inline QMultiMap<QByteArray, QByteArray> getUploadedFiles() const noexcept { return httpParser->getUploadedFiles(); }
  157. /**
  158. * @brief Fill a QObject using parameters of a HTTP message.
  159. * @param QObject *object : Object to be filled.
  160. * @par Example
  161. * @code
  162. * //----------------bmi.view----------------
  163. *
  164. * <?xml version="1.0" encoding="iso-8859-1" ?>
  165. * <html>
  166. * <head>
  167. * <title>Body Mass Index (BMI)</title>
  168. * </head>
  169. * <body>
  170. * <form method="POST" action="/bmi">
  171. * Name<br/><input type="text" name="name"/><br/>
  172. * Mass(KG)<br/><input type="text" name="mass"/><br/>
  173. * Height(m)<br/><input type="text" name="height"/><br/><br/>
  174. * <input type="submit" name="submit" value="Calculate"/>
  175. * </form>
  176. * </body>
  177. * </html>
  178. *
  179. * //----------------bmiresults.view----------------
  180. *
  181. * <?xml version="1.0" encoding="iso-8859-1" ?>
  182. * <html>
  183. * <head>
  184. * <title>Body Mass Index (BMI) - Results</title>
  185. * </head>
  186. * <body>
  187. * Name: <out value="#{user.getName}"/><br/>
  188. * Mass(KG): <out value="#{user.getMass}"/><br/>
  189. * Height(m): <out value="#{user.getHeight}"/><br/>
  190. * BMI: <out value="#{user.getBmi}"/><br/>
  191. * Category: <out value="#{user.getCategory}"/>
  192. * </body>
  193. * </html>
  194. *
  195. * //----------------user.h----------------
  196. *
  197. * #ifndef USER_H
  198. * #define USER_H
  199. *
  200. * #include <QObject>
  201. * #include <QString>
  202. *
  203. * class User : public QObject
  204. * {
  205. * Q_OBJECT
  206. * private:
  207. * QString name;
  208. * QString category;
  209. * double mass = 0;
  210. * double height = 0;
  211. * double bmi = 0;
  212. * public:
  213. * explicit User(QObject *parent = 0) : QObject(parent)
  214. * {
  215. * }
  216. * public slots:
  217. * QString getName() const
  218. * {
  219. * return name;
  220. * }
  221. * void setName(const QString &value)
  222. * {
  223. * name = value;
  224. * }
  225. * QString getCategory() const
  226. * {
  227. * return category;
  228. * }
  229. * double getMass() const
  230. * {
  231. * return mass;
  232. * }
  233. * void setMass(double value)
  234. * {
  235. * mass = value;
  236. * }
  237. * double getHeight() const
  238. * {
  239. * return height;
  240. * }
  241. * void setHeight(double value)
  242. * {
  243. * height = value;
  244. * }
  245. * double getBmi()
  246. * {
  247. * bmi = height != 0 ? mass / (height * height) : 0;
  248. *
  249. * if(bmi <= 15)
  250. * {
  251. * category = "Very severely underweight";
  252. * }
  253. * else if(bmi > 15 && bmi <= 16)
  254. * {
  255. * category = "Severely underweight";
  256. * }
  257. * else if(bmi > 16 && bmi <= 18.5)
  258. * {
  259. * category = "Underweight";
  260. * }
  261. * else if(bmi > 18.5 && bmi <= 25)
  262. * {
  263. * category = "Normal (healthy weight)";
  264. * }
  265. * else if(bmi > 25 && bmi <= 30)
  266. * {
  267. * category = "Overweight";
  268. * }
  269. * else if(bmi > 30 && bmi <= 35)
  270. * {
  271. * category = "Obese Class I (Moderately obese)";
  272. * }
  273. * else if(bmi > 35 && bmi <= 40)
  274. * {
  275. * category = "Obese Class II (Severely obese)";
  276. * }
  277. * else
  278. * {
  279. * category = "Obese Class III (Very severely obese)";
  280. * }
  281. *
  282. * return bmi;
  283. * }
  284. * };
  285. *
  286. * #endif // USER_H
  287. *
  288. * //----------------bmicontroller.h----------------
  289. *
  290. * #ifndef BMICONTROLLER_H
  291. * #define BMICONTROLLER_H
  292. *
  293. * #include "cwf/controller.h"
  294. * #include "cwf/request.h"
  295. * #include "cwf/response.h"
  296. * #include "entities/user.h"
  297. *
  298. * class BmiController : public CWF::Controller
  299. * {
  300. * public:
  301. * void doGet(CWF::Request &request, CWF::Response &response) override
  302. * {
  303. * request.getRequestDispatcher("/pages/bmi").forward(request, response);
  304. * }
  305. * void doPost(CWF::Request &request, CWF::Response &response) override
  306. * {
  307. * User user;
  308. * request.fillQObject(&user);
  309. * request.addAttribute("user", &user);
  310. * request.getRequestDispatcher("/pages/bmiresults.view").forward(request, response);
  311. * }
  312. * };
  313. *
  314. * #endif // BMICONTROLLER_H
  315. *
  316. * //----------------main.cpp----------------
  317. *
  318. * #include <QCoreApplication>
  319. * #include <cwf/cppwebapplication.h>
  320. * #include <controllers/bmicontroller.h>
  321. *
  322. * int main(int argc, char *argv[])
  323. * {
  324. * CWF::CppWebApplication server(argc, argv, "PATH_TO_SERVER_FOLDER");
  325. *
  326. * server.addUrlController<BmiController>("/bmi");
  327. *
  328. * return server.start();
  329. * }
  330. * @endcode
  331. */
  332. void fillQObject(QObject *object, bool urlDecode = true, bool replacePlusForSpace = true);
  333. void fillQObject(QObject *object,
  334. const QMap<QByteArray, QByteArray> &parameters,
  335. bool urlDecode = true, bool replacePlusForSpace = true);
  336. };
  337. CWF_END_NAMESPACE
  338. #endif // Request_H