bool HttpHandlerQtScript::handleRequest(Pillow::HttpRequest *request) { if (!_scriptFunction.isFunction()) return false; QScriptEngine* engine = _scriptFunction.engine(); QScriptValue requestObject = engine->newObject(); requestObject.setProperty("nativeRequest", _scriptFunction.engine()->newQObject(request)); requestObject.setProperty("requestMethod", QUrl::fromPercentEncoding(request->requestMethod())); requestObject.setProperty("requestUri", QUrl::fromPercentEncoding(request->requestUri())); requestObject.setProperty("requestFragment", QUrl::fromPercentEncoding(request->requestFragment())); requestObject.setProperty("requestPath", QUrl::fromPercentEncoding(request->requestPath())); requestObject.setProperty("requestQueryString", QUrl::fromPercentEncoding(request->requestQueryString())); requestObject.setProperty("requestHeaders", qScriptValueFromValue(engine, request->requestHeaders())); QList<QPair<QString, QString> > queryParams = QUrl(request->requestUri()).queryItems(); QScriptValue queryParamsObject = engine->newObject(); for (int i = 0, iE = queryParams.size(); i < iE; ++i) queryParamsObject.setProperty(queryParams.at(i).first, queryParams.at(i).second); requestObject.setProperty("requestQueryParams", queryParamsObject); QScriptValue result = _scriptFunction.call(_scriptFunction, QScriptValueList() << requestObject); if (result.isError()) { if (request->state() == HttpRequest::SendingHeaders) { // Nothing was sent yet... We have a chance to let the client know we had an error. request->writeResponseString(500, HttpHeaderCollection(), objectToString(result)); } engine->clearExceptions(); return true; } return result.toBool(); }
void handleException() { Q_ASSERT( m_engine ); Q_ASSERT( m_engine->hasUncaughtException() ); const QString err = m_engine->uncaughtException().toString(); const int linenr = m_engine->uncaughtExceptionLineNumber(); const QString trace = m_engine->uncaughtExceptionBacktrace().join("\n"); qrossdebug( QString("%1, line:%2, backtrace:\n%3").arg(err).arg(linenr).arg(trace) ); m_script->action()->setError(err, trace, linenr); m_engine->clearExceptions(); }
QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined) { Q_ASSERT(context() && context()->engine); DeleteWatcher watcher(this); QDeclarativeEngine *engine = context()->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); QDeclarativeContextData *oldSharedContext = 0; QObject *oldSharedScope = 0; QObject *oldOverride = 0; bool isShared = (expressionFunctionMode == SharedContext); if (isShared) { oldSharedContext = ep->sharedContext; oldSharedScope = ep->sharedScope; ep->sharedContext = context(); ep->sharedScope = scopeObject; } else { oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope); } QScriptValue thisObject; if (evalFlags & RequiresThisObject) thisObject = ep->objectClass->newQObject(scopeObject); QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted if (isShared) { ep->sharedContext = oldSharedContext; ep->sharedScope = oldSharedScope; } else if (!watcher.wasDeleted()) { ep->contextClass->setOverrideObject(expressionContext, oldOverride); } if (isUndefined) *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); // Handle exception if (scriptEngine->hasUncaughtException()) { if (!watcher.wasDeleted()) QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error); scriptEngine->clearExceptions(); return QScriptValue(); } else { if (!watcher.wasDeleted()) error = QDeclarativeError(); return svalue; } }
static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { if (engine.hasUncaughtException()) { const auto backtrace = engine.uncaughtExceptionBacktrace(); const auto exception = engine.uncaughtException().toString(); const auto line = QString::number(engine.uncaughtExceptionLineNumber()); engine.clearExceptions(); auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); if (!backtrace.empty()) { static const auto lineSeparator = "\n "; message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); } qWarning() << qPrintable(message); return true; } return false; }
QVariant QDeclarativeExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined) { QDeclarativeExpressionData *data = this->data; QDeclarativeEngine *engine = data->context()->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); if (!data->expressionFunctionValid) { QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); data->expressionContext = ep->contextClass->newContext(data->context(), data->me); scriptContext->pushScope(data->expressionContext); scriptContext->pushScope(ep->globalClass->globalObject()); if (data->expressionRewritten) { data->expressionFunction = scriptEngine->evaluate(data->expression, data->url, data->line); } else { QDeclarativeRewrite::RewriteBinding rewriteBinding; bool ok = true; const QString code = rewriteBinding(data->expression, &ok); if (!ok) { scriptEngine->popContext(); return QVariant(); } data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line); } scriptEngine->popContext(); data->expressionFunctionValid = true; } QDeclarativeContextData *oldSharedContext = 0; QObject *oldSharedScope = 0; QObject *oldOverride = 0; if (data->isShared) { oldSharedContext = ep->sharedContext; oldSharedScope = ep->sharedScope; ep->sharedContext = data->context(); ep->sharedScope = data->me; } else { oldOverride = ep->contextClass->setOverrideObject(data->expressionContext, secondaryScope); } QScriptValue svalue = data->expressionFunction.call(); if (data->isShared) { ep->sharedContext = oldSharedContext; ep->sharedScope = oldSharedScope; } else { ep->contextClass->setOverrideObject(data->expressionContext, oldOverride); } if (isUndefined) *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); // Handle exception if (scriptEngine->hasUncaughtException()) { exceptionToError(scriptEngine, data->error); scriptEngine->clearExceptions(); return QVariant(); } else { data->error = QDeclarativeError(); } QVariant rv; if (svalue.isArray()) { int length = svalue.property(QLatin1String("length")).toInt32(); if (length && svalue.property(0).isObject()) { QList<QObject *> list; for (int ii = 0; ii < length; ++ii) { QScriptValue arrayItem = svalue.property(ii); QObject *d = arrayItem.toQObject(); list << d; } rv = QVariant::fromValue(list); } } else if (svalue.isObject() && ep->objectClass->scriptClass(svalue) == ep->objectClass) { QObject *o = svalue.toQObject(); int type = QMetaType::QObjectStar; // If the object is null, we extract the predicted type. While this isn't // 100% reliable, in many cases it gives us better error messages if we // assign this null-object to an incompatible property if (!o) type = ep->objectClass->objectType(svalue); return QVariant(type, &o); } if (rv.isNull()) rv = svalue.toVariant(); return rv; }
/*! Applies the given \a command to the given \a backend. */ QScriptDebuggerResponse QScriptDebuggerCommandExecutor::execute( QScriptDebuggerBackend *backend, const QScriptDebuggerCommand &command) { QScriptDebuggerResponse response; switch (command.type()) { case QScriptDebuggerCommand::None: break; case QScriptDebuggerCommand::Interrupt: backend->interruptEvaluation(); break; case QScriptDebuggerCommand::Continue: if (backend->engine()->isEvaluating()) { backend->continueEvalution(); response.setAsync(true); } break; case QScriptDebuggerCommand::StepInto: { QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount); int count = attr.isValid() ? attr.toInt() : 1; backend->stepInto(count); response.setAsync(true); } break; case QScriptDebuggerCommand::StepOver: { QVariant attr = command.attribute(QScriptDebuggerCommand::StepCount); int count = attr.isValid() ? attr.toInt() : 1; backend->stepOver(count); response.setAsync(true); } break; case QScriptDebuggerCommand::StepOut: backend->stepOut(); response.setAsync(true); break; case QScriptDebuggerCommand::RunToLocation: backend->runToLocation(command.fileName(), command.lineNumber()); response.setAsync(true); break; case QScriptDebuggerCommand::RunToLocationByID: backend->runToLocation(command.scriptId(), command.lineNumber()); response.setAsync(true); break; case QScriptDebuggerCommand::ForceReturn: { int contextIndex = command.contextIndex(); QScriptDebuggerValue value = command.scriptValue(); QScriptEngine *engine = backend->engine(); QScriptValue realValue = value.toScriptValue(engine); backend->returnToCaller(contextIndex, realValue); response.setAsync(true); } break; case QScriptDebuggerCommand::Resume: backend->resume(); response.setAsync(true); break; case QScriptDebuggerCommand::SetBreakpoint: { QScriptBreakpointData data = command.breakpointData(); if (!data.isValid()) data = QScriptBreakpointData(command.fileName(), command.lineNumber()); int id = backend->setBreakpoint(data); response.setResult(id); } break; case QScriptDebuggerCommand::DeleteBreakpoint: { int id = command.breakpointId(); if (!backend->deleteBreakpoint(id)) response.setError(QScriptDebuggerResponse::InvalidBreakpointID); } break; case QScriptDebuggerCommand::DeleteAllBreakpoints: backend->deleteAllBreakpoints(); break; case QScriptDebuggerCommand::GetBreakpoints: { QScriptBreakpointMap bps = backend->breakpoints(); if (!bps.isEmpty()) response.setResult(bps); } break; case QScriptDebuggerCommand::GetBreakpointData: { int id = command.breakpointId(); QScriptBreakpointData data = backend->breakpointData(id); if (data.isValid()) response.setResult(data); else response.setError(QScriptDebuggerResponse::InvalidBreakpointID); } break; case QScriptDebuggerCommand::SetBreakpointData: { int id = command.breakpointId(); QScriptBreakpointData data = command.breakpointData(); if (!backend->setBreakpointData(id, data)) response.setError(QScriptDebuggerResponse::InvalidBreakpointID); } break; case QScriptDebuggerCommand::GetScripts: { QScriptScriptMap scripts = backend->scripts(); if (!scripts.isEmpty()) response.setResult(scripts); } break; case QScriptDebuggerCommand::GetScriptData: { qint64 id = command.scriptId(); QScriptScriptData data = backend->scriptData(id); if (data.isValid()) response.setResult(data); else response.setError(QScriptDebuggerResponse::InvalidScriptID); } break; case QScriptDebuggerCommand::ScriptsCheckpoint: backend->scriptsCheckpoint(); response.setResult(QVariant::fromValue(backend->scriptsDelta())); break; case QScriptDebuggerCommand::GetScriptsDelta: response.setResult(QVariant::fromValue(backend->scriptsDelta())); break; case QScriptDebuggerCommand::ResolveScript: response.setResult(backend->resolveScript(command.fileName())); break; case QScriptDebuggerCommand::GetBacktrace: response.setResult(backend->backtrace()); break; case QScriptDebuggerCommand::GetContextCount: response.setResult(backend->contextCount()); break; case QScriptDebuggerCommand::GetContextState: { QScriptContext *ctx = backend->context(command.contextIndex()); if (ctx) response.setResult(static_cast<int>(ctx->state())); else response.setError(QScriptDebuggerResponse::InvalidContextIndex); } break; case QScriptDebuggerCommand::GetContextID: { int idx = command.contextIndex(); if ((idx >= 0) && (idx < backend->contextCount())) response.setResult(backend->contextIds()[idx]); else response.setError(QScriptDebuggerResponse::InvalidContextIndex); } break; case QScriptDebuggerCommand::GetContextInfo: { QScriptContext *ctx = backend->context(command.contextIndex()); if (ctx) response.setResult(QScriptContextInfo(ctx)); else response.setError(QScriptDebuggerResponse::InvalidContextIndex); } break; case QScriptDebuggerCommand::GetThisObject: { QScriptContext *ctx = backend->context(command.contextIndex()); if (ctx) response.setResult(ctx->thisObject()); else response.setError(QScriptDebuggerResponse::InvalidContextIndex); } break; case QScriptDebuggerCommand::GetActivationObject: { QScriptContext *ctx = backend->context(command.contextIndex()); if (ctx) response.setResult(ctx->activationObject()); else response.setError(QScriptDebuggerResponse::InvalidContextIndex); } break; case QScriptDebuggerCommand::GetScopeChain: { QScriptContext *ctx = backend->context(command.contextIndex()); if (ctx) { QScriptDebuggerValueList dest; QScriptValueList src = ctx->scopeChain(); for (int i = 0; i < src.size(); ++i) dest.append(src.at(i)); response.setResult(dest); } else { response.setError(QScriptDebuggerResponse::InvalidContextIndex); } } break; case QScriptDebuggerCommand::ContextsCheckpoint: { response.setResult(QVariant::fromValue(backend->contextsCheckpoint())); } break; case QScriptDebuggerCommand::GetPropertyExpressionValue: { QScriptContext *ctx = backend->context(command.contextIndex()); int lineNumber = command.lineNumber(); QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute); QStringList path = attr.toStringList(); if (!ctx || path.isEmpty()) break; QScriptContextInfo ctxInfo(ctx); if (ctx->callee().isValid() && ((lineNumber < ctxInfo.functionStartLineNumber()) || (lineNumber > ctxInfo.functionEndLineNumber()))) { break; } QScriptValueList objects; int pathIndex = 0; if (path.at(0) == QLatin1String("this")) { objects.append(ctx->thisObject()); ++pathIndex; } else { objects << ctx->scopeChain(); } for (int i = 0; i < objects.size(); ++i) { QScriptValue val = objects.at(i); for (int j = pathIndex; val.isValid() && (j < path.size()); ++j) { val = val.property(path.at(j)); } if (val.isValid()) { bool hadException = (ctx->state() == QScriptContext::ExceptionState); QString str = val.toString(); if (!hadException && backend->engine()->hasUncaughtException()) backend->engine()->clearExceptions(); response.setResult(str); break; } } } break; case QScriptDebuggerCommand::GetCompletions: { QScriptContext *ctx = backend->context(command.contextIndex()); QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute); QStringList path = attr.toStringList(); if (!ctx || path.isEmpty()) break; QScriptValueList objects; QString prefix = path.last(); QSet<QString> matches; if (path.size() > 1) { const QString &topLevelIdent = path.at(0); QScriptValue obj; if (topLevelIdent == QLatin1String("this")) { obj = ctx->thisObject(); } else { QScriptValueList scopeChain; scopeChain = ctx->scopeChain(); for (int i = 0; i < scopeChain.size(); ++i) { QScriptValue oo = scopeChain.at(i).property(topLevelIdent); if (oo.isObject()) { obj = oo; break; } } } for (int i = 1; obj.isObject() && (i < path.size()-1); ++i) obj = obj.property(path.at(i)); if (obj.isValid()) objects.append(obj); } else { objects << ctx->scopeChain(); QStringList keywords; keywords.append(QString::fromLatin1("this")); keywords.append(QString::fromLatin1("true")); keywords.append(QString::fromLatin1("false")); keywords.append(QString::fromLatin1("null")); for (int i = 0; i < keywords.size(); ++i) { const QString &kwd = keywords.at(i); if (isPrefixOf(prefix, kwd)) matches.insert(kwd); } } for (int i = 0; i < objects.size(); ++i) { QScriptValue obj = objects.at(i); while (obj.isObject()) { QScriptValueIterator it(obj); while (it.hasNext()) { it.next(); QString propertyName = it.name(); if (isPrefixOf(prefix, propertyName)) matches.insert(propertyName); } obj = obj.prototype(); } } QStringList matchesList = matches.toList(); qStableSort(matchesList); response.setResult(matchesList); } break; case QScriptDebuggerCommand::NewScriptObjectSnapshot: { int id = backend->newScriptObjectSnapshot(); response.setResult(id); } break; case QScriptDebuggerCommand::ScriptObjectSnapshotCapture: { int id = command.snapshotId(); QScriptObjectSnapshot *snap = backend->scriptObjectSnapshot(id); Q_ASSERT(snap != 0); QScriptDebuggerValue object = command.scriptValue(); Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue); QScriptEngine *engine = backend->engine(); QScriptValue realObject = object.toScriptValue(engine); Q_ASSERT(realObject.isObject()); QScriptObjectSnapshot::Delta delta = snap->capture(realObject); QScriptDebuggerObjectSnapshotDelta result; result.removedProperties = delta.removedProperties; bool didIgnoreExceptions = backend->ignoreExceptions(); backend->setIgnoreExceptions(true); for (int i = 0; i < delta.changedProperties.size(); ++i) { const QScriptValueProperty &src = delta.changedProperties.at(i); bool hadException = engine->hasUncaughtException(); QString str = src.value().toString(); if (!hadException && engine->hasUncaughtException()) engine->clearExceptions(); QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags()); result.changedProperties.append(dest); } for (int j = 0; j < delta.addedProperties.size(); ++j) { const QScriptValueProperty &src = delta.addedProperties.at(j); bool hadException = engine->hasUncaughtException(); QString str = src.value().toString(); if (!hadException && engine->hasUncaughtException()) engine->clearExceptions(); QScriptDebuggerValueProperty dest(src.name(), src.value(), str, src.flags()); result.addedProperties.append(dest); } backend->setIgnoreExceptions(didIgnoreExceptions); response.setResult(QVariant::fromValue(result)); } break; case QScriptDebuggerCommand::DeleteScriptObjectSnapshot: { int id = command.snapshotId(); backend->deleteScriptObjectSnapshot(id); } break; case QScriptDebuggerCommand::NewScriptValueIterator: { QScriptDebuggerValue object = command.scriptValue(); Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue); QScriptEngine *engine = backend->engine(); QScriptValue realObject = object.toScriptValue(engine); Q_ASSERT(realObject.isObject()); int id = backend->newScriptValueIterator(realObject); response.setResult(id); } break; case QScriptDebuggerCommand::GetPropertiesByIterator: { int id = command.iteratorId(); int count = 1000; QScriptValueIterator *it = backend->scriptValueIterator(id); Q_ASSERT(it != 0); QScriptDebuggerValuePropertyList props; for (int i = 0; (i < count) && it->hasNext(); ++i) { it->next(); QString name = it->name(); QScriptValue value = it->value(); QString valueAsString = value.toString(); QScriptValue::PropertyFlags flags = it->flags(); QScriptDebuggerValueProperty prp(name, value, valueAsString, flags); props.append(prp); } response.setResult(props); } break; case QScriptDebuggerCommand::DeleteScriptValueIterator: { int id = command.iteratorId(); backend->deleteScriptValueIterator(id); } break; case QScriptDebuggerCommand::Evaluate: { int contextIndex = command.contextIndex(); QString program = command.program(); QString fileName = command.fileName(); int lineNumber = command.lineNumber(); backend->evaluate(contextIndex, program, fileName, lineNumber); response.setAsync(true); } break; case QScriptDebuggerCommand::ScriptValueToString: { QScriptDebuggerValue value = command.scriptValue(); QScriptEngine *engine = backend->engine(); QScriptValue realValue = value.toScriptValue(engine); response.setResult(realValue.toString()); } break; case QScriptDebuggerCommand::SetScriptValueProperty: { QScriptDebuggerValue object = command.scriptValue(); QScriptEngine *engine = backend->engine(); QScriptValue realObject = object.toScriptValue(engine); QScriptDebuggerValue value = command.subordinateScriptValue(); QScriptValue realValue = value.toScriptValue(engine); QString name = command.name(); realObject.setProperty(name, realValue); } break; case QScriptDebuggerCommand::ClearExceptions: backend->engine()->clearExceptions(); break; case QScriptDebuggerCommand::UserCommand: case QScriptDebuggerCommand::MaxUserCommand: break; } return response; }
void tst_QScriptContext::pushAndPopScope() { QScriptEngine eng; QScriptContext *ctx = eng.currentContext(); QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject())); QVERIFY(ctx->popScope().strictlyEquals(eng.globalObject())); ctx->pushScope(eng.globalObject()); QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject())); QScriptValue obj = eng.newObject(); ctx->pushScope(obj); QCOMPARE(ctx->scopeChain().size(), 2); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(obj)); QVERIFY(ctx->scopeChain().at(1).strictlyEquals(eng.globalObject())); QVERIFY(ctx->popScope().strictlyEquals(obj)); QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject())); { QScriptValue ret = eng.evaluate("x"); QVERIFY(ret.isError()); eng.clearExceptions(); } QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject())); // task 236685 QScriptValue qobj = eng.newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::AutoCreateDynamicProperties); ctx->pushScope(qobj); QCOMPARE(ctx->scopeChain().size(), 2); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(qobj)); QVERIFY(ctx->scopeChain().at(1).strictlyEquals(eng.globalObject())); { QScriptValue ret = eng.evaluate("print"); QVERIFY(ret.isFunction()); } ctx->popScope(); ctx->pushScope(obj); QCOMPARE(ctx->scopeChain().size(), 2); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(obj)); obj.setProperty("x", 123); { QScriptValue ret = eng.evaluate("x"); QVERIFY(ret.isNumber()); QCOMPARE(ret.toInt32(), 123); } QVERIFY(ctx->popScope().strictlyEquals(obj)); QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->scopeChain().at(0).strictlyEquals(eng.globalObject())); ctx->pushScope(QScriptValue()); QCOMPARE(ctx->scopeChain().size(), 1); QVERIFY(ctx->popScope().strictlyEquals(eng.globalObject())); QVERIFY(ctx->scopeChain().isEmpty()); // Used to work with old back-end, doesn't with new one because JSC requires that the last object in // a scope chain is the Global Object. QTest::ignoreMessage(QtWarningMsg, "QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object"); ctx->pushScope(obj); QCOMPARE(ctx->scopeChain().size(), 0); QScriptEngine eng2; QScriptValue obj2 = eng2.newObject(); QTest::ignoreMessage(QtWarningMsg, "QScriptContext::pushScope() failed: cannot push an object created in a different engine"); ctx->pushScope(obj2); QVERIFY(ctx->scopeChain().isEmpty()); QVERIFY(!ctx->popScope().isValid()); }