Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/src/org/labkey/api/action/ApiResponseWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.json.JSONObject;
import org.labkey.api.query.BatchValidationException;
import org.labkey.api.query.PropertyValidationError;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.SimpleValidationError;
import org.labkey.api.query.ValidationError;
import org.labkey.api.query.ValidationException;
Expand Down Expand Up @@ -445,7 +446,7 @@ public JSONObject toJSON(Throwable e)
json.put("errors", arr);
json.put("errorCount", arr.length());
json.put("exception", message);
json.put("extraContext", bve.getExtraContext());
json.put(QueryService.EXTRA_CONTEXT, bve.getExtraContext());

return json;
}
Expand Down
3 changes: 2 additions & 1 deletion api/src/org/labkey/api/data/triggers/ScriptTrigger.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.labkey.api.data.PHI;
import org.labkey.api.data.TableInfo;
import org.labkey.api.query.BatchValidationException;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.ValidationException;
import org.labkey.api.script.ScriptReference;
import org.labkey.api.security.User;
Expand Down Expand Up @@ -258,7 +259,7 @@ private <T> T _try(Container c, User user, Map<String, Object> extraContext, Scr
Map<String, Object> bindings = new HashMap<>();
if (extraContext == null)
extraContext = new HashMap<>();
bindings.put("extraContext", extraContext);
bindings.put(QueryService.EXTRA_CONTEXT, extraContext);
bindings.put("schemaName", _table.getPublicSchemaName());
bindings.put("tableName", _table.getPublicName());

Expand Down
2 changes: 2 additions & 0 deletions api/src/org/labkey/api/query/QueryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public interface QueryService

String SCHEMA_TEMPLATE_EXTENSION = ".template.xml";

String EXTRA_CONTEXT = "extraContext";

static QueryService get()
{
return ServiceRegistry.get().getService(QueryService.class);
Expand Down
48 changes: 44 additions & 4 deletions core/src/org/labkey/core/script/RhinoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
package org.labkey.core.script;

import com.sun.phobos.script.javascript.RhinoScriptEngineFactory;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
Expand All @@ -35,6 +36,7 @@
import org.labkey.api.module.ModuleResourceCaches;
import org.labkey.api.module.ResourceRootProvider;
import org.labkey.api.query.BatchValidationException;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.ValidationException;
import org.labkey.api.reader.Readers;
import org.labkey.api.resource.Resource;
Expand All @@ -58,6 +60,7 @@
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrapFactory;
Expand Down Expand Up @@ -237,8 +240,8 @@ public void testModuleResourceCache()

if (null != simpleTest)
{
assertEquals("Scripts from the simpletest module", 15, ScriptReferenceImpl.SCRIPT_CACHE.getResourceMap(simpleTest).size());
assertEquals("Top-level script timestamps from the simpletest module", 15, LabKeyModuleSourceProvider.TOP_LEVEL_SCRIPT_CACHE.getResourceMap(simpleTest).size());
assertEquals("Scripts from the simpletest module", 16, ScriptReferenceImpl.SCRIPT_CACHE.getResourceMap(simpleTest).size());
assertEquals("Top-level script timestamps from the simpletest module", 16, LabKeyModuleSourceProvider.TOP_LEVEL_SCRIPT_CACHE.getResourceMap(simpleTest).size());
}
}
}
Expand Down Expand Up @@ -1006,7 +1009,7 @@ protected void observeInstructionCount(Context cx, int instructionCount)
{
SandboxContext ctx = (SandboxContext)cx;
long currentTime = HeartBeat.currentTimeMillis();
final int timeout = 60;
final long timeout = ctx.getTimeout();
if (currentTime - ctx.startTime > timeout*1000)
Context.reportError("Script execution exceeded " + timeout + " seconds.");
}
Expand Down Expand Up @@ -1043,6 +1046,10 @@ public boolean visibleToScripts(String fullClassName)

private static class SandboxContext extends Context
{
private static final String SCRIPT_TIMEOUT_PROPERTY = "scriptTimeout";
private static final int MAX_ALLOWABLE_TIMEOUT = 300;
private final long DEFAULT_TIMEOUT = 60;

private final long startTime;

private SandboxContext(SandboxContextFactory factory)
Expand All @@ -1051,6 +1058,39 @@ private SandboxContext(SandboxContextFactory factory)
setLanguageVersion(Context.VERSION_1_8);
startTime = HeartBeat.currentTimeMillis();
}

public long getTimeout()
{
if (ScriptRuntime.hasTopCall(this))
{
Scriptable script = ScriptRuntime.getTopCallScope(this);
Object o = ScriptRuntime.getObjectProp(script, QueryService.EXTRA_CONTEXT, this);
if (o instanceof ScriptableMap mp)
{
if (mp.getMap().get(SCRIPT_TIMEOUT_PROPERTY) != null)
{
Object rawTimeout = mp.getMap().get(SCRIPT_TIMEOUT_PROPERTY);
try
{
int scriptTimeout = Integer.parseInt(String.valueOf(rawTimeout));
if (scriptTimeout > MAX_ALLOWABLE_TIMEOUT)
{
scriptTimeout = MAX_ALLOWABLE_TIMEOUT;
LOG.error("Script timeout is greater than max allowable, using: {}", MAX_ALLOWABLE_TIMEOUT);
}

return scriptTimeout;
}
catch (Exception e)
{
LOG.error("Non-integer value provided to extractContext.scriptTimeout for script: {}", rawTimeout);
}
}
}
}

return DEFAULT_TIMEOUT;
}
}

private static class SandboxWrapFactory extends WrapFactory
Expand Down
10 changes: 5 additions & 5 deletions query/src/org/labkey/query/controllers/QueryController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4643,7 +4643,7 @@ protected JSONObject executeJson(JSONObject json, CommandType commandType, boole
}
}

Map<String, Object> extraContext = json.has("extraContext") ? json.getJSONObject("extraContext").toMap() : new CaseInsensitiveHashMap<>();
Map<String, Object> extraContext = json.has(QueryService.EXTRA_CONTEXT) ? json.getJSONObject(QueryService.EXTRA_CONTEXT).toMap() : new CaseInsensitiveHashMap<>();

Map<String, Object> auditDetails = json.has("auditDetails") ? json.getJSONObject("auditDetails").toMap() : new CaseInsensitiveHashMap<>();

Expand Down Expand Up @@ -5138,7 +5138,7 @@ else if (scope != tableInfo.getSchema().getScope())
}

JSONArray resultArray = new JSONArray();
JSONObject extraContext = json.optJSONObject("extraContext");
JSONObject extraContext = json.optJSONObject(QueryService.EXTRA_CONTEXT);
JSONObject auditDetails = json.optJSONObject("auditDetails");

int startingErrorIndex = 0;
Expand All @@ -5162,11 +5162,11 @@ else if (scope != tableInfo.getSchema().getScope())
Map<String, Object> commandExtraContext = new HashMap<>();
if (extraContext != null)
commandExtraContext.putAll(extraContext.toMap());
if (commandObject.has("extraContext"))
if (commandObject.has(QueryService.EXTRA_CONTEXT))
{
commandExtraContext.putAll(commandObject.getJSONObject("extraContext").toMap());
commandExtraContext.putAll(commandObject.getJSONObject(QueryService.EXTRA_CONTEXT).toMap());
}
commandObject.put("extraContext", commandExtraContext);
commandObject.put(QueryService.EXTRA_CONTEXT, commandExtraContext);
Map<String, Object> commandAuditDetails = new HashMap<>();
if (auditDetails != null)
commandAuditDetails.putAll(auditDetails.toMap());
Expand Down