Skip to content

Commit

Permalink
parse all inputs on initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
rPraml committed Dec 13, 2024
1 parent 9558aca commit 659ebc5
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public void quit(Context cx, int exitCode) {
*/
public static void main(String args[]) {
try {
if (RhinoConfig.getBoolean("rhino.use_java_policy_security")) {
if (RhinoConfig.DEFAULT.useJavaPolicySecurity()) {
initJavaPolicySecuritySupport();
}
} catch (SecurityException ex) {
Expand Down
226 changes: 148 additions & 78 deletions rhino/src/main/java/org/mozilla/javascript/RhinoConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

/**
* Utility class to read current rhino configuration.
Expand All @@ -30,96 +28,68 @@
* <li>env variables starting with "RHINO_" (underscores are replaced by '.' and string is
* </ol>
*
* The config files are in UTF-8 format and all keys in this configuration are case-insensitive and
* dot/underscore-insensitive.
* <p>The config files are in UTF-8 format and all keys in this configuration are case-insensitive
* and dot/underscore-insensitive.
*
* <p>This means, "rhino.use_java_policy_security" is equvalent to "RHINO_USE_JAVA_POLICY_SECURITY"
*
* @author Roland Praml, Foconis Analytics GmbH
*/
public class RhinoConfig {
private static final Map<String, String> PROPERTIES =
AccessController.doPrivileged((PrivilegedAction<Map<String, String>>) () -> init());

private static Map<String, String> init() {
// we have to add a comparator at least for environment: TODO: can this done simpler
Comparator<String> comparator =
(s1, s2) -> {
s1 = s1.toLowerCase(Locale.ROOT).replace('_', '.');
s2 = s2.toLowerCase(Locale.ROOT).replace('_', '.');
return s1.compareTo(s2);
};
Map<String, String> map = new TreeMap<>(comparator);

// load from classpaths
map.putAll(loadFromClasspath(RhinoConfig.class.getClassLoader()));
map.putAll(loadFromClasspath(Thread.currentThread().getContextClassLoader()));
map.putAll(loadFromFile(new File("rhino.config")));
copyMap(System.getProperties(), map);
copyMap(System.getenv(), map);
System.out.println("Current config: " + map);
return map;
}

/** Copies all rhino relevant properties. */
private static void copyMap(Map<?, ?> src, Map<String, String> dst) {
for (Map.Entry<?, ?> entry : src.entrySet()) {
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
String key = (String) entry.getKey();
if (key.startsWith("rhino.") || key.startsWith("RHINO_")) {
dst.put(key, (String) entry.getValue());
}
}

public static final RhinoConfig DEFAULT =
AccessController.doPrivileged((PrivilegedAction<RhinoConfig>) () -> init());

private static RhinoConfig init() {
RhinoConfig config = new RhinoConfig();
// we parse the following locations
config.loadFromClasspath(RhinoConfig.class.getClassLoader());
config.loadFromClasspath(Thread.currentThread().getContextClassLoader());
config.loadFromFile(new File("rhino.config"));
config.load(System.getProperties(), "System.properties");
config.load(System.getenv(), "System.env");
return config;
}

private void loadFromFile(File config) {
if (!config.exists()) {
return;
}
try (InputStream in = new FileInputStream(config)) {
Properties props = new Properties();
props.load(new InputStreamReader(in, StandardCharsets.UTF_8));
load(props, config.getAbsolutePath());
} catch (IOException e) {
System.err.println(
"Error loading rhino.config from "
+ config.getAbsolutePath()
+ ": "
+ e.getMessage());
}
}

@SuppressWarnings("unchecked")
private static Map<String, String> loadFromFile(File config) {
if (config.exists()) {
try (InputStream in = new FileInputStream(config)) {
if (in != null) {
Properties props = new Properties();
props.load(new InputStreamReader(in, StandardCharsets.UTF_8));
System.out.println(
"Loaded rhino.config from "
+ config.getAbsolutePath()); // TODO: remove these prints
return (Map) props;
}
} catch (IOException e) {
System.err.println(
"Error loading rhino.config from "
+ config.getAbsolutePath()
+ ": "
+ e.getMessage());
}
@SuppressWarnings("unchecked")
private void loadFromClasspath(ClassLoader cl) {
if (cl == null) {
return;
}
return Collections.emptyMap();
}

@SuppressWarnings("unchecked")
private static Map<String, String> loadFromClasspath(ClassLoader cl) {
if (cl != null) {
try (InputStream in = cl.getResourceAsStream("rhino.config")) {
if (in != null) {
Properties props = new Properties();
props.load(new InputStreamReader(in, StandardCharsets.UTF_8));
System.out.println(
"Loaded "
+ props.size()
+ " proerties from rhino.config in classpath"); // TODO: remove
// these prints
return (Map) props;
}
} catch (IOException e) {
System.err.println("Error loading rhino.config from classpath: " + e.getMessage());
}
URL resource = cl.getResource("rhino.config");
if (resource == null) {
return;
}
try (InputStream in = resource.openStream()) {
Properties props = new Properties();
props.load(new InputStreamReader(in, StandardCharsets.UTF_8));
load(props, resource.toString());
} catch (IOException e) {
System.err.println(
"Error loading rhino.config from " + resource + ": " + e.getMessage());
}
return Collections.emptyMap();
}

/** Replacement for {@link System#getProperty(String)}. */
public static String getProperty(String key) {
return PROPERTIES.get(key);
return null;
}

/** Replacement for {@link System#getProperty(String, String)}. */
Expand Down Expand Up @@ -164,4 +134,104 @@ public static Integer getInteger(String nm, int val) {
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}

/** Returns the property as string. */
private String get(Map map, String property, String defaultValue) {
Object ret = find(map, property);
if (ret == null) {
return defaultValue;
} else {
return ret.toString();
}
}

/** Returns the property as enum. */
private <T extends Enum<T>> T get(Map map, String property, T defaultValue) {
Object ret = map.get(property);
if (ret == null) {
return defaultValue;
} else {
Class<T> enumType = (Class<T>) defaultValue.getClass();
return Enum.valueOf(enumType, ret.toString().toUpperCase(Locale.ROOT));
}
}

/** Returns the property as boolean. */
private boolean get(Map map, String property, boolean defaultValue) {
Object ret = map.get(property);
if (ret == null) {
return defaultValue;
} else if (ret instanceof Boolean) {
return (Boolean) ret;
} else {
return "1".equals(ret) || "true".equals(ret);
}
}

/**
* Tries to find the property in the map. It tries the property first, then it tries the camel
* upper version.
*/
private Object find(Map map, String property) {
Object ret = map.get(property);
if (ret != null) {
return ret;
}
return map.get(toCamelUpper(property));
}

private String toCamelUpper(String property) {
String s = property.replace('.', '_');
StringBuilder sb = new StringBuilder(s.length() + 5);
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (i > 0 && Character.isUpperCase(c) && Character.isLowerCase(s.charAt(i - 1))) {
sb.append('_');
}
sb.append(Character.toUpperCase(c));
}
return sb.toString();
}

private void load(Map map, String location) {
stackStyle = get(map, "rhino.stack.style", stackStyle);
useJavaPolicySecurity = get(map, "rhino.use_java_policy_security", useJavaPolicySecurity);
printTrees = get(map, "rhino.printTrees", printTrees);
printICodes = get(map, "rhino.printICodes", printICodes);
debugStack = get(map, "rhino.debugStack", debugStack);
debugLinker = get(map, "rhino.debugLinker", debugStack);
}

/** "rhino.stack.style" */
private StackStyle stackStyle;

private boolean useJavaPolicySecurity;
private boolean printTrees = false;
private boolean printICodes = false;
private boolean debugStack = false;
private boolean debugLinker = false;

public StackStyle stackStyle() {
return stackStyle;
}

public boolean useJavaPolicySecurity() {
return useJavaPolicySecurity;
}

public boolean printTrees() {
return printTrees;
}

public boolean printICodes() {
return printICodes;
}

public boolean debugStack() {
return debugStack;
}

public boolean debugLinker() {
return debugLinker;
}
}
16 changes: 1 addition & 15 deletions rhino/src/main/java/org/mozilla/javascript/RhinoException.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public static StackStyle getStackStyle() {
private static final long serialVersionUID = 1883500631321581169L;

// Just for testing!
private static StackStyle stackStyle = StackStyle.RHINO;
private static StackStyle stackStyle = RhinoConfig.DEFAULT.stackStyle();

private String sourceName;
private int lineNumber;
Expand All @@ -383,18 +383,4 @@ public static StackStyle getStackStyle() {

Object interpreterStackInfo;
int[] interpreterLineData;

// Allow us to override default stack style for debugging.
static {
String style = RhinoConfig.getProperty("rhino.stack.style");
if (style != null) {
if ("Rhino".equalsIgnoreCase(style)) {
stackStyle = StackStyle.RHINO;
} else if ("Mozilla".equalsIgnoreCase(style)) {
stackStyle = StackStyle.MOZILLA;
} else if ("V8".equalsIgnoreCase(style)) {
stackStyle = StackStyle.V8;
}
}
}
}
4 changes: 2 additions & 2 deletions rhino/src/main/java/org/mozilla/javascript/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public static enum CommentType {
}

// debug flags
public static final boolean printTrees = false;
static final boolean printICode = false;
public static final boolean printTrees = RhinoConfig.DEFAULT.printTrees();
static final boolean printICode = RhinoConfig.DEFAULT.printICodes();
static final boolean printNames = printTrees || printICode;

/** Token types. These values correspond to JSTokenType values in jsscan.c. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import jdk.dynalink.linker.LinkerServices;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.RhinoConfig;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Token;
Expand All @@ -22,15 +23,7 @@
*/
@SuppressWarnings("AndroidJdkLibsChecker")
class DefaultLinker implements GuardingDynamicLinker {
static final boolean DEBUG;

static {
String debugVal = System.getProperty("RHINO_DEBUG_LINKER");
if (debugVal == null) {
debugVal = System.getenv("RHINO_DEBUG_LINKER");
}
DEBUG = Boolean.parseBoolean(debugVal);
}
static final boolean DEBUG = RhinoConfig.DEFAULT.debugLinker();

@Override
public GuardedInvocation getGuardedInvocation(LinkRequest req, LinkerServices svc)
Expand Down

0 comments on commit 659ebc5

Please sign in to comment.