cutelyst  3.7.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
session.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "session_p.h"
6 
7 #include "sessionstorefile.h"
8 
9 #include <Cutelyst/Application>
10 #include <Cutelyst/Context>
11 #include <Cutelyst/Response>
12 #include <Cutelyst/Engine>
13 
14 #include <QUuid>
15 #include <QHostAddress>
16 #include <QLoggingCategory>
17 #include <QCoreApplication>
18 
19 using namespace Cutelyst;
20 
21 Q_LOGGING_CATEGORY(C_SESSION, "cutelyst.plugin.session", QtWarningMsg)
22 
23 #define SESSION_VALUES QStringLiteral("_c_session_values")
24 #define SESSION_EXPIRES QStringLiteral("_c_session_expires")
25 #define SESSION_TRIED_LOADING_EXPIRES QStringLiteral("_c_session_tried_loading_expires")
26 #define SESSION_EXTENDED_EXPIRES QStringLiteral("_c_session_extended_expires")
27 #define SESSION_UPDATED QStringLiteral("_c_session_updated")
28 #define SESSION_ID QStringLiteral("_c_session_id")
29 #define SESSION_TRIED_LOADING_ID QStringLiteral("_c_session_tried_loading_id")
30 #define SESSION_DELETED_ID QStringLiteral("_c_session_deleted_id")
31 #define SESSION_DELETE_REASON QStringLiteral("_c_session_delete_reason")
32 
33 static thread_local Session *m_instance = nullptr;
34 
36  , d_ptr(new SessionPrivate(this))
37 {
38 
39 }
40 
41 Cutelyst::Session::~Session()
42 {
43  delete d_ptr;
44 }
45 
47 {
48  Q_D(Session);
49  d->sessionName = QCoreApplication::applicationName() + QLatin1String("_session");
50 
51  const QVariantMap config = app->engine()->config(QLatin1String("Cutelyst_Session_Plugin"));
52  d->sessionExpires = config.value(QLatin1String("expires"), 7200).toLongLong();
53  d->expiryThreshold = config.value(QLatin1String("expiry_threshold"), 0).toLongLong();
54  d->verifyAddress = config.value(QLatin1String("verify_address"), false).toBool();
55  d->verifyUserAgent = config.value(QLatin1String("verify_user_agent"), false).toBool();
56  d->cookieHttpOnly = config.value(QLatin1String("cookie_http_only"), true).toBool();
57  d->cookieSecure = config.value(QLatin1String("cookie_secure"), false).toBool();
58  const QString _sameSite = config.value(QLatin1String("cookie_same_site"), QStringLiteral("strict")).toString();
59 #if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
60  if (_sameSite.compare(u"default", Qt::CaseInsensitive) == 0) {
61  d->cookieSameSite = QNetworkCookie::SameSite::Default;
62  } else if (_sameSite.compare(u"none", Qt::CaseInsensitive) == 0) {
63  d->cookieSameSite = QNetworkCookie::SameSite::None;
64  } else if (_sameSite.compare(u"lax", Qt::CaseInsensitive) == 0) {
65  d->cookieSameSite = QNetworkCookie::SameSite::Lax;
66  } else {
67  d->cookieSameSite = QNetworkCookie::SameSite::Strict;
68  }
69 #else
70  if (_sameSite.compare(u"default", Qt::CaseInsensitive) == 0) {
71  d->cookieSameSite = Cookie::SameSite::Default;
72  } else if (_sameSite.compare(u"none", Qt::CaseInsensitive) == 0) {
73  d->cookieSameSite = Cookie::SameSite::None;
74  } else if (_sameSite.compare(u"lax", Qt::CaseInsensitive) == 0) {
75  d->cookieSameSite = Cookie::SameSite::Lax;
76  } else {
77  d->cookieSameSite = Cookie::SameSite::Strict;
78  }
79 #endif
80 
81  connect(app, &Application::afterDispatch, this, &SessionPrivate::_q_saveSession);
82  connect(app, &Application::postForked, this, [=] {
83  m_instance = this;
84  });
85 
86  if (!d->store) {
87  d->store = new SessionStoreFile(this);
88  }
89 
90  return true;
91 }
92 
94 {
95  Q_D(Session);
96  Q_ASSERT_X(d->store, "Cutelyst::Session::setStorage", "Session Storage is alread defined");
97  store->setParent(this);
98  d->store = store;
99 }
100 
102 {
103  Q_D(const Session);
104  return d->store;
105 }
106 
108 {
109  QString ret;
110  const QVariant sid = c->stash(SESSION_ID);
111  if (sid.isNull()) {
112  if (Q_UNLIKELY(!m_instance)) {
113  qCCritical(C_SESSION) << "Session plugin not registered";
114  return ret;
115  }
116 
117  ret = SessionPrivate::loadSessionId(c, m_instance->d_ptr->sessionName);
118  } else {
119  ret = sid.toString();
120  }
121 
122  return ret;
123 }
124 
126 {
127  QVariant expires = c->stash(SESSION_EXTENDED_EXPIRES);
128  if (!expires.isNull()) {
129  return expires.toULongLong();
130  }
131 
132  if (Q_UNLIKELY(!m_instance)) {
133  qCCritical(C_SESSION) << "Session plugin not registered";
134  return 0;
135  }
136 
137  expires = SessionPrivate::loadSessionExpires(m_instance, c, id(c));
138  if (!expires.isNull()) {
139  return quint64(SessionPrivate::extendSessionExpires(m_instance, c, expires.toLongLong()));
140  }
141 
142  return 0;
143 }
144 
145 void Session::changeExpires(Context *c, quint64 expires)
146 {
147  const QString sid = Session::id(c);
148  const qint64 timeExp = QDateTime::currentMSecsSinceEpoch() / 1000 + qint64(expires);
149 
150  if (Q_UNLIKELY(!m_instance)) {
151  qCCritical(C_SESSION) << "Session plugin not registered";
152  return;
153  }
154 
155  m_instance->d_ptr->store->storeSessionData(c, sid, QStringLiteral("expires"), timeExp);
156 }
157 
158 void Session::deleteSession(Context *c, const QString &reason)
159 {
160  if (Q_UNLIKELY(!m_instance)) {
161  qCCritical(C_SESSION) << "Session plugin not registered";
162  return;
163  }
164  SessionPrivate::deleteSession(m_instance, c, reason);
165 }
166 
168 {
169  return c->stash(SESSION_DELETE_REASON).toString();
170 }
171 
172 QVariant Session::value(Cutelyst::Context *c, const QString &key, const QVariant &defaultValue)
173 {
174  QVariant ret = defaultValue;
175  QVariant session = c->stash(SESSION_VALUES);
176  if (session.isNull()) {
177  session = SessionPrivate::loadSession(c);
178  }
179 
180  if (!session.isNull()) {
181  ret = session.toHash().value(key, defaultValue);
182  }
183 
184  return ret;
185 }
186 
187 void Session::setValue(Cutelyst::Context *c, const QString &key, const QVariant &value)
188 {
189  QVariant session = c->stash(SESSION_VALUES);
190  if (session.isNull()) {
191  session = SessionPrivate::loadSession(c);
192  if (session.isNull()) {
193  if (Q_UNLIKELY(!m_instance)) {
194  qCCritical(C_SESSION) << "Session plugin not registered";
195  return;
196  }
197 
198  SessionPrivate::createSessionIdIfNeeded(m_instance, c, m_instance->d_ptr->sessionExpires);
199  session = SessionPrivate::initializeSessionData(m_instance, c);
200  }
201  }
202 
203  QVariantHash data = session.toHash();
204  data.insert(key, value);
205 
206  c->setStash(SESSION_VALUES, data);
207  c->setStash(SESSION_UPDATED, true);
208 }
209 
211 {
212  QVariant session = c->stash(SESSION_VALUES);
213  if (session.isNull()) {
214  session = SessionPrivate::loadSession(c);
215  if (session.isNull()) {
216  if (Q_UNLIKELY(!m_instance)) {
217  qCCritical(C_SESSION) << "Session plugin not registered";
218  return;
219  }
220 
221  SessionPrivate::createSessionIdIfNeeded(m_instance, c, m_instance->d_ptr->sessionExpires);
222  session = SessionPrivate::initializeSessionData(m_instance, c);
223  }
224  }
225 
226  QVariantHash data = session.toHash();
227  data.remove(key);
228 
229  c->setStash(SESSION_VALUES, data);
230  c->setStash(SESSION_UPDATED, true);
231 }
232 
234 {
235  QVariant session = c->stash(SESSION_VALUES);
236  if (session.isNull()) {
237  session = SessionPrivate::loadSession(c);
238  if (session.isNull()) {
239  if (Q_UNLIKELY(!m_instance)) {
240  qCCritical(C_SESSION) << "Session plugin not registered";
241  return;
242  }
243 
244  SessionPrivate::createSessionIdIfNeeded(m_instance, c, m_instance->d_ptr->sessionExpires);
245  session = SessionPrivate::initializeSessionData(m_instance, c);
246  }
247  }
248 
249  QVariantHash data = session.toHash();
250  for (const QString &key : keys) {
251  data.remove(key);
252  }
253 
254  c->setStash(SESSION_VALUES, data);
255  c->setStash(SESSION_UPDATED, true);
256 }
257 
259 {
260  return !SessionPrivate::loadSession(c).isNull();
261 }
262 
263 QString SessionPrivate::generateSessionId()
264 {
265  return QString::fromLatin1(QUuid::createUuid().toRfc4122().toHex());
266 }
267 
268 QString SessionPrivate::loadSessionId(Context *c, const QString &sessionName)
269 {
270  QString ret;
271  if (!c->stash(SESSION_TRIED_LOADING_ID).isNull()) {
272  return ret;
273  }
274  c->setStash(SESSION_TRIED_LOADING_ID, true);
275 
276  const QString sid = getSessionId(c, sessionName);
277  if (!sid.isEmpty()) {
278  if (!validateSessionId(sid)) {
279  qCCritical(C_SESSION) << "Tried to set invalid session ID" << sid;
280  return ret;
281  }
282  ret = sid;
283  c->setStash(SESSION_ID, sid);
284  }
285 
286  return ret;
287 }
288 
289 QString SessionPrivate::getSessionId(Context *c, const QString &sessionName)
290 {
291  QString ret;
292  bool deleted = !c->stash(SESSION_DELETED_ID).isNull();
293 
294  if (!deleted) {
295  const QVariant property = c->stash(SESSION_ID);
296  if (!property.isNull()) {
297  ret = property.toString();
298  return ret;
299  }
300 
301  const QString cookie = c->request()->cookie(sessionName);
302  if (!cookie.isEmpty()) {
303  qCDebug(C_SESSION) << "Found sessionid" << cookie << "in cookie";
304  ret = cookie;
305  }
306  }
307 
308  return ret;
309 }
310 
311 QString SessionPrivate::createSessionIdIfNeeded(Session *session, Context *c, qint64 expires)
312 {
313  QString ret;
314  const QVariant sid = c->stash(SESSION_ID);
315  if (!sid.isNull()) {
316  ret = sid.toString();
317  } else {
318  ret = createSessionId(session, c, expires);
319  }
320  return ret;
321 }
322 
323 QString SessionPrivate::createSessionId(Session *session, Context *c, qint64 expires)
324 {
325  Q_UNUSED(expires)
326  const QString sid = generateSessionId();
327 
328  qCDebug(C_SESSION) << "Created session" << sid;
329 
330  c->setStash(SESSION_ID, sid);
331  resetSessionExpires(session, c, sid);
332  setSessionId(session, c, sid);
333 
334  return sid;
335 }
336 
337 void SessionPrivate::_q_saveSession(Context *c)
338 {
339  // fix cookie before we send headers
340  saveSessionExpires(c);
341 
342  // Force extension of session_expires before finalizing headers, so a pos
343  // up to date. First call to session_expires will extend the expiry, methods
344  // just return the previously extended value.
345  Session::expires(c);
346 
347  // Persist data
348  if (Q_UNLIKELY(!m_instance)) {
349  qCCritical(C_SESSION) << "Session plugin not registered";
350  return;
351  }
352  saveSessionExpires(c);
353 
354  if (!c->stash(SESSION_UPDATED).toBool()) {
355  return;
356  }
357  SessionStore *store = m_instance->d_ptr->store;
358  QVariantHash sessionData = c->stash(SESSION_VALUES).toHash();
359  sessionData.insert(QStringLiteral("__updated"), QDateTime::currentMSecsSinceEpoch() / 1000);
360 
361  const QString sid = c->stash(SESSION_ID).toString();
362  store->storeSessionData(c, sid, QStringLiteral("session"), sessionData);
363 }
364 
365 void SessionPrivate::deleteSession(Session *session, Context *c, const QString &reason)
366 {
367  qCDebug(C_SESSION) << "Deleting session" << reason;
368 
369  const QVariant sidVar = c->stash(SESSION_ID).toString();
370  if (!sidVar.isNull()) {
371  const QString sid = sidVar.toString();
372  session->d_ptr->store->deleteSessionData(c, sid, QStringLiteral("session"));
373  session->d_ptr->store->deleteSessionData(c, sid, QStringLiteral("expires"));
374  session->d_ptr->store->deleteSessionData(c, sid, QStringLiteral("flash"));
375 
376  deleteSessionId(session, c, sid);
377  }
378 
379  // Reset the values in Context object
380  c->setStash(SESSION_VALUES, QVariant());
381  c->setStash(SESSION_ID, QVariant());
382  c->setStash(SESSION_EXPIRES, QVariant());
383 
384  c->setStash(SESSION_DELETE_REASON, reason);
385 }
386 
387 void SessionPrivate::deleteSessionId(Session *session, Context *c, const QString &sid)
388 {
389  c->setStash(SESSION_DELETED_ID, true); // to prevent get_session_id from returning it
390 
391 #if (QT_VERSION >= QT_VERSION_CHECK(6, 1, 0))
392  updateSessionCookie(c, makeSessionCookie(session, c, sid, QDateTime::currentDateTimeUtc()));
393 #else
394  updateSessionCuteCookie(c, makeSessionCuteCookie(session, c, sid, QDateTime::currentDateTimeUtc()));
395 #endif
396 }
397 
398 QVariant SessionPrivate::loadSession(Context *c)
399 {
400  QVariant ret;
401  const QVariant property = c->stash(SESSION_VALUES);
402  if (!property.isNull()) {
403  ret = property.toHash();
404  return ret;
405  }
406 
407  if (Q_UNLIKELY(!m_instance)) {
408  qCCritical(C_SESSION) << "Session plugin not registered";
409  return ret;
410  }
411 
412  const QString sid = Session::id(c);
413  if (!loadSessionExpires(m_instance, c, sid).isNull()) {
414  if (SessionPrivate::validateSessionId(sid)) {
415 
416  const QVariantHash sessionData = m_instance->d_ptr->store->getSessionData(c, sid, QStringLiteral("session")).toHash();
417  c->setStash(SESSION_VALUES, sessionData);
418 
419  if (m_instance->d_ptr->verifyAddress &&
420  sessionData.contains(QStringLiteral("__address")) &&
421  sessionData.value(QStringLiteral("__address")).toString() != c->request()->address().toString()) {
422  qCWarning(C_SESSION) << "Deleting session" << sid << "due to address mismatch:"
423  << sessionData.value(QStringLiteral("__address")).toString()
424  << "!="
425  << c->request()->address().toString();
426  deleteSession(m_instance, c, QStringLiteral("address mismatch"));
427  return ret;
428  }
429 
430  if (m_instance->d_ptr->verifyUserAgent &&
431  sessionData.contains(QStringLiteral("__user_agent")) &&
432  sessionData.value(QStringLiteral("__user_agent")).toString() != c->request()->userAgent()) {
433  qCWarning(C_SESSION) << "Deleting session" << sid << "due to user agent mismatch:"
434  << sessionData.value(QStringLiteral("__user_agent")).toString()
435  << "!="
436  << c->request()->userAgent();
437  deleteSession(m_instance, c, QStringLiteral("user agent mismatch"));
438  return ret;
439  }
440 
441  qCDebug(C_SESSION) << "Restored session" << sid;
442 
443  ret = sessionData;
444  }
445  }
446 
447  return ret;
448 }
449 
450 bool SessionPrivate::validateSessionId(const QString &id)
451 {
452  auto it = id.constBegin();
453  auto end = id.constEnd();
454  while (it != end) {
455  QChar c = *it;
456  if ((c >= u'a' && c <= u'f') || (c >= u'0' && c <= u'9')) {
457  ++it;
458  continue;
459  }
460  return false;
461  }
462 
463  return id.size();
464 }
465 
466 qint64 SessionPrivate::extendSessionExpires(Session *session, Context *c, qint64 expires)
467 {
468  const qint64 threshold = qint64(session->d_ptr->expiryThreshold);
469 
470  const QString sid = Session::id(c);
471  if (!sid.isEmpty()) {
472  const qint64 current = getStoredSessionExpires(session, c, sid);
473  const qint64 cutoff = current - threshold;
474  const qint64 time = QDateTime::currentMSecsSinceEpoch() / 1000;
475 
476  if (!threshold || cutoff <= time || c->stash(SESSION_UPDATED).toBool()) {
477  qint64 updated = calculateInitialSessionExpires(session, c, sid);
478  c->setStash(SESSION_EXTENDED_EXPIRES, updated);
479  extendSessionId(session, c, sid, updated);
480 
481  return updated;
482  } else {
483  return current;
484  }
485  } else {
486  return expires;
487  }
488 }
489 
490 qint64 SessionPrivate::getStoredSessionExpires(Session *session, Context *c, const QString &sessionid)
491 {
492  const QVariant expires = session->d_ptr->store->getSessionData(c, sessionid, QStringLiteral("expires"), 0);
493  return expires.toLongLong();
494 }
495 
496 QVariant SessionPrivate::initializeSessionData(Session *session, Context *c)
497 {
498  QVariantHash ret;
499  const qint64 now = QDateTime::currentMSecsSinceEpoch() / 1000;
500  ret.insert(QStringLiteral("__created"), now);
501  ret.insert(QStringLiteral("__updated"), now);
502 
503  if (session->d_ptr->verifyAddress) {
504  ret.insert(QStringLiteral("__address"), c->request()->address().toString());
505  }
506 
507  if (session->d_ptr->verifyUserAgent) {
508  ret.insert(QStringLiteral("__user_agent"), c->request()->userAgent());
509  }
510 
511  return ret;
512 }
513 
514 void SessionPrivate::saveSessionExpires(Context *c)
515 {
516  const QVariant expires = c->stash(SESSION_EXPIRES);
517  if (!expires.isNull()) {
518  const QString sid = Session::id(c);
519  if (!sid.isEmpty()) {
520  if (Q_UNLIKELY(!m_instance)) {
521  qCCritical(C_SESSION) << "Session plugin not registered";
522  return;
523  }
524 
525  const qint64 current = getStoredSessionExpires(m_instance, c, sid);
526  const qint64 extended = qint64(Session::expires(c));
527  if (extended > current) {
528  m_instance->d_ptr->store->storeSessionData(c, sid, QStringLiteral("expires"), extended);
529  }
530  }
531  }
532 }
533 
534 QVariant SessionPrivate::loadSessionExpires(Session *session, Context *c, const QString &sessionId)
535 {
536  QVariant ret;
537  if (c->stash(SESSION_TRIED_LOADING_EXPIRES).toBool()) {
538  ret = c->stash(SESSION_EXPIRES);
539  return ret;
540  }
541  c->setStash(SESSION_TRIED_LOADING_EXPIRES, true);
542 
543  if (!sessionId.isEmpty()) {
544  const qint64 expires = getStoredSessionExpires(session, c, sessionId);
545 
546  if (expires >= QDateTime::currentMSecsSinceEpoch() / 1000) {
547  c->setStash(SESSION_EXPIRES, expires);
548  ret = expires;
549  } else {
550  deleteSession(session, c, QStringLiteral("session expired"));
551  ret = 0;
552  }
553  }
554  return ret;
555 }
556 
557 qint64 SessionPrivate::initialSessionExpires(Session *session, Context *c)
558 {
559  Q_UNUSED(c)
560  const qint64 expires = qint64(session->d_ptr->sessionExpires);
561  return QDateTime::currentMSecsSinceEpoch() / 1000 + expires;
562 }
563 
564 qint64 SessionPrivate::calculateInitialSessionExpires(Session *session, Context *c, const QString &sessionId)
565 {
566  const qint64 stored = getStoredSessionExpires(session, c, sessionId);
567  const qint64 initial = initialSessionExpires(session, c);
568  return qMax(initial , stored);
569 }
570 
571 qint64 SessionPrivate::resetSessionExpires(Session *session, Context *c, const QString &sessionId)
572 {
573  const qint64 exp = calculateInitialSessionExpires(session, c, sessionId);
574 
575  c->setStash(SESSION_EXPIRES, exp);
576 
577  // since we're setting _session_expires directly, make loadSessionExpires
578  // actually use that value.
579  c->setStash(SESSION_TRIED_LOADING_EXPIRES, true);
580  c->setStash(SESSION_EXTENDED_EXPIRES, exp);
581 
582  return exp;
583 }
584 
585 void SessionPrivate::updateSessionCookie(Context *c, const QNetworkCookie &updated)
586 {
587  c->response()->setCookie(updated);
588 }
589 
590 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
591 void SessionPrivate::updateSessionCuteCookie(Context *c, const Cookie &updated)
592 {
593  c->response()->setCuteCookie(updated);
594 }
595 #endif
596 
597 QNetworkCookie SessionPrivate::makeSessionCookie(Session *session, Context *c, const QString &sid, const QDateTime &expires)
598 {
599  Q_UNUSED(c)
600  QNetworkCookie cookie(session->d_ptr->sessionName.toLatin1(), sid.toLatin1());
601  cookie.setPath(QStringLiteral("/"));
602  cookie.setExpirationDate(expires);
603  cookie.setHttpOnly(session->d_ptr->cookieHttpOnly);
604  cookie.setSecure(session->d_ptr->cookieSecure);
605 #if (QT_VERSION >= QT_VERSION_CHECK(6, 1, 0))
606  cookie.setSameSitePolicy(session->d_ptr->cookieSameSite);
607 #endif
608 
609  return cookie;
610 }
611 
612 #if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
613 Cookie SessionPrivate::makeSessionCuteCookie(Session *session, Context *c, const QString &sid, const QDateTime &expires)
614 {
615  Q_UNUSED(c)
616  Cookie cookie(session->d_ptr->sessionName.toLatin1(), sid.toLatin1());
617  cookie.setPath(QStringLiteral("/"));
618  cookie.setExpirationDate(expires);
619  cookie.setHttpOnly(session->d_ptr->cookieHttpOnly);
620  cookie.setSecure(session->d_ptr->cookieSecure);
621  cookie.setSameSitePolicy(session->d_ptr->cookieSameSite);
622 
623  return cookie;
624 }
625 #endif
626 
627 void SessionPrivate::extendSessionId(Session *session, Context *c, const QString &sid, qint64 expires)
628 {
629 #if (QT_VERSION >= QT_VERSION_CHECK(6, 1, 0))
630  updateSessionCookie(c, makeSessionCookie(session, c, sid, QDateTime::fromMSecsSinceEpoch(expires * 1000)));
631 #else
632  updateSessionCuteCookie(c, makeSessionCuteCookie(session, c, sid, QDateTime::fromMSecsSinceEpoch(expires * 1000)));
633 #endif
634 }
635 
636 void SessionPrivate::setSessionId(Session *session, Context *c, const QString &sid)
637 {
638 #if (QT_VERSION >= QT_VERSION_CHECK(6, 1, 0))
639  updateSessionCookie(c, makeSessionCookie(session, c, sid,
640  QDateTime::fromMSecsSinceEpoch(initialSessionExpires(session, c) * 1000)));
641 #else
642  updateSessionCuteCookie(c, makeSessionCuteCookie(session, c, sid,
643  QDateTime::fromMSecsSinceEpoch(initialSessionExpires(session, c) * 1000)));
644 #endif
645 }
646 
648 {
649 
650 }
651 
652 #include "moc_session.cpp"
The Cutelyst Application.
Definition: application.h:43
Engine * engine() const noexcept
void afterDispatch(Cutelyst::Context *c)
void postForked(Cutelyst::Application *app)
The Cutelyst Context.
Definition: context.h:39
void stash(const QVariantHash &unite)
Definition: context.cpp:546
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:218
Response * response() const noexcept
Definition: context.cpp:97
The Cutelyst Cookie.
Definition: cookie.h:29
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:292
QString cookie(const QString &name) const
Definition: request.cpp:272
QHostAddress address() const noexcept
Definition: request.cpp:33
void setCookie(const QNetworkCookie &cookie)
Definition: response.cpp:231
SessionStore(QObject *parent=nullptr)
Definition: session.cpp:647
virtual bool storeSessionData(Context *c, const QString &sid, const QString &key, const QVariant &value)=0
static void deleteSession(Context *c, const QString &reason=QString())
Definition: session.cpp:158
static QString deleteReason(Context *c)
Definition: session.cpp:167
virtual bool setup(Application *app) final
Definition: session.cpp:46
Session(Application *parent)
Definition: session.cpp:35
static QString id(Context *c)
Definition: session.cpp:107
static bool isValid(Context *c)
Definition: session.cpp:258
static QVariant value(Context *c, const QString &key, const QVariant &defaultValue=QVariant())
Definition: session.cpp:172
static void setValue(Context *c, const QString &key, const QVariant &value)
Definition: session.cpp:187
static void changeExpires(Context *c, quint64 expires)
Definition: session.cpp:145
SessionStore * storage() const
Definition: session.cpp:101
void setStorage(SessionStore *store)
Definition: session.cpp:93
static void deleteValue(Context *c, const QString &key)
Definition: session.cpp:210
static quint64 expires(Context *c)
Definition: session.cpp:125
static void deleteValues(Context *c, const QStringList &keys)
Definition: session.cpp:233
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8
QDateTime currentDateTimeUtc()
qint64 currentMSecsSinceEpoch()
QDateTime fromMSecsSinceEpoch(qint64 msecs)
QString toString() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setParent(QObject *parent)
int compare(const QString &other, Qt::CaseSensitivity cs) const const
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
QByteArray toLatin1() const const
CaseInsensitive
QUuid createUuid()
bool isNull() const const
QHash< QString, QVariant > toHash() const const
qlonglong toLongLong(bool *ok) const const
QString toString() const const