18 #include "context_p.h"
24 #include "dispatcher.h"
25 #include "controller.h"
26 #include "application.h"
28 #include "enginerequest.h"
34 #include <QCoreApplication>
44 d_ptr(new ContextPrivate(app, app->engine(), app->dispatcher(), app->plugins()))
46 auto req =
new DummyRequest(
this);
47 req->
body =
new QBuffer(
this);
48 req->
body->open(QBuffer::ReadWrite);
52 d_ptr->request =
new Request(req);
53 d_ptr->request->d_ptr->engine = d_ptr->engine;
58 delete d_ptr->request;
59 delete d_ptr->response;
66 return !d->error.isEmpty();
72 if (
error.isEmpty()) {
76 qCCritical(CUTELYST_CORE) <<
error;
86 bool Context::state()
const
122 Action *Context::action()
const
128 QString Context::actionName()
const
131 return d->action->name();
134 QString Context::ns()
const
137 return d->action->ns();
140 Request *Context::request()
const
155 return d->dispatcher;
158 QString Cutelyst::Context::controllerName()
const
161 return QString::fromLatin1(d->action->controller()->metaObject()->className());
167 return d->action->controller();
173 return d->dispatcher->controllers().value(name);
185 return d->app->view(name);
191 d->view = d->app->view(name);
204 return d->stash.value(key);
210 return d->stash.value(key, defaultValue);
216 return d->stash.take(key);
222 return d->stash.remove(key);
228 d->stash.insert(key, value);
234 d->stash.insert(key, QVariant::fromValue(map));
247 QUrl uri = d->request->uri();
250 if (path.isEmpty()) {
252 const QString controllerNS = d->action->controller()->ns();
253 if (!controllerNS.isEmpty()) {
254 _path.prepend(controllerNS);
260 if (!args.isEmpty()) {
261 if (_path == QLatin1String(
"/")) {
262 _path += args.join(QLatin1Char(
'/'));
264 _path = _path + QLatin1Char(
'/') + args.join(QLatin1Char(
'/'));
268 if (!_path.startsWith(QLatin1Char(
'/'))) {
269 _path.prepend(QLatin1Char(
'/'));
271 uri.setPath(_path, QUrl::DecodedMode);
274 if (!queryValues.isEmpty()) {
276 if (queryValues.size()) {
277 auto it = queryValues.constEnd();
278 while (it != queryValues.constBegin()) {
280 query.addQueryItem(it.key(), it.value());
294 Action *localAction = action;
296 localAction = d->action;
299 QStringList localArgs = args;
300 QStringList localCaptures = captures;
302 Action *expandedAction = d->dispatcher->expandAction(
this, action);
305 && localArgs.size()) {
306 localCaptures.append(localArgs.takeFirst());
309 QStringList localCapturesAux = localCaptures;
310 localCapturesAux.append(localArgs);
311 localArgs = localCapturesAux;
312 localCaptures = QStringList();
315 const QString path = d->dispatcher->uriForAction(localAction, localCaptures);
316 if (path.isEmpty()) {
317 qCWarning(CUTELYST_CORE) <<
"Can not find action for" << localAction << localCaptures;
321 uri =
uriFor(path, localArgs, queryValues);
330 Action *action = d->dispatcher->getActionByPath(path);
332 qCWarning(CUTELYST_CORE) <<
"Can not find action for" << path;
336 uri =
uriFor(action, captures, args, queryValues);
350 d->dispatcher->forward(
this, action);
359 d->asyncDetached =
true;
360 d->engineRequest->status |= EngineRequest::Async;
366 bool &asyncDetached = d->asyncDetached;
367 asyncDetached =
false;
369 while (!d->pendingAsync.isEmpty()) {
370 Component *action = d->pendingAsync.takeLast();
373 }
else if (asyncDetached) {
378 if (d->engineRequest->status & EngineRequest::Async) {
379 Q_EMIT d->app->afterDispatch(
this);
388 return d->dispatcher->forward(
this, action);
394 return d->dispatcher->forward(
this, action);
400 return d->dispatcher->getAction(action, ns);
406 return d->dispatcher->getActions(action, ns);
418 Q_ASSERT_X(code,
"Context::execute",
"trying to execute a null Cutelyst::Component");
420 static int recursion = qEnvironmentVariableIsSet(
"RECURSION") ? qEnvironmentVariableIntValue(
"RECURSION") : 1000;
421 if (d->stack.size() >= recursion) {
422 QString msg = QStringLiteral(
"Deep recursion detected (stack size %1) calling %2, %3")
423 .arg(QString::number(d->stack.size()), code->
reverse(), code->
name());
433 const QString statsInfo = d->statsStartExecute(code);
437 if (!statsInfo.isEmpty()) {
438 d->statsFinishExecute(statsInfo);
461 QVariant Context::config(
const QString &key,
const QVariant &defaultValue)
const
464 return d->app->config(key, defaultValue);
467 QVariantMap Context::config()
const
470 return d->app->config();
473 QString
Context::translate(
const char *context,
const char *sourceText,
const char *disambiguation,
int n)
const
476 return d->app->translate(d->locale, context, sourceText, disambiguation, n);
497 void Context::finalize()
502 qCDebug(CUTELYST_STATS,
"Response Code: %d; Content-Type: %s; Content-Length: %s",
503 d->response->status(),
504 qPrintable(d->response->headers().header(QStringLiteral(
"CONTENT_TYPE"), QStringLiteral(
"unknown"))),
505 qPrintable(d->response->headers().header(QStringLiteral(
"CONTENT_LENGTH"), QStringLiteral(
"unknown"))));
507 const double enlapsed = d->engineRequest->elapsed.nsecsElapsed() / 1000000000.0;
509 if (enlapsed == 0.0) {
510 average = QStringLiteral(
"??");
512 average = QString::number(1.0 / enlapsed,
'f');
513 average.truncate(average.size() - 3);
515 qCInfo(CUTELYST_STATS) << qPrintable(QStringLiteral(
"Request took: %1s (%2/s)\n%3")
516 .arg(QString::number(enlapsed,
'f'),
518 QString::fromLatin1(d->stats->report())));
523 d->engineRequest->finalize();
539 QString ContextPrivate::statsStartExecute(
Component *code)
543 if (code->
name().startsWith(QLatin1Char(
'_'))) {
549 if (qobject_cast<Action *>(code)) {
550 actionName.prepend(QLatin1Char(
'/'));
553 if (stack.size() > 2) {
554 actionName = QLatin1String(
"-> ") + actionName;
555 actionName = actionName.rightJustified(actionName.size() + stack.size() - 2, QLatin1Char(
' '));
558 stats->profileStart(actionName);
563 void ContextPrivate::statsFinishExecute(
const QString &statsInfo)
565 stats->profileEnd(statsInfo);
568 #include "moc_context.cpp"
569 #include "moc_context_p.cpp"