You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/01/12 11:09:19 UTC
[struts] 01/03: WW-5054 Allows omit class/packages restrictions in
devMode
This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch WW-5054-debug-browser
in repository https://gitbox.apache.org/repos/asf/struts.git
commit 8326535c3e2637352f8d4b7801059fbf34ee4e46
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sun Jan 12 12:07:56 2020 +0100
WW-5054 Allows omit class/packages restrictions in devMode
---
.../com/opensymphony/xwork2/ognl/OgnlUtil.java | 39 ++++++-
.../debugging/DebuggingInterceptor.java | 128 +++++++++++----------
.../interceptor/debugging/ObjectToHTMLWriter.java | 36 ++++--
3 files changed, 126 insertions(+), 77 deletions(-)
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
index 01d5374..9798974 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java
@@ -65,6 +65,10 @@ public class OgnlUtil {
private Set<Pattern> excludedPackageNamePatterns;
private Set<String> excludedPackageNames;
+ private Set<Class<?>> excludedClassesCopy;
+ private Set<Pattern> excludedPackageNamePatternsCopy;
+ private Set<String> excludedPackageNamesCopy;
+
private Container container;
private boolean allowStaticFieldAccess = true;
private boolean allowStaticMethodAccess;
@@ -111,6 +115,33 @@ public class OgnlUtil {
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
}
+ public void avoidAccessControl() {
+ if (devMode) {
+ LOG.warn("Cleans up excluded classes and packages in devMode");
+ excludedClassesCopy = new HashSet<>(excludedClasses);
+ excludedClasses = Collections.unmodifiableSet(new HashSet<>());
+
+ excludedPackageNamePatternsCopy = new HashSet<>(excludedPackageNamePatterns);
+ excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
+
+ excludedPackageNamesCopy = new HashSet<>(excludedPackageNames);
+ excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
+ }
+ }
+ public void restoreAccessControl() {
+ if (devMode) {
+ LOG.warn("Restores excluded classes and packages in devMode");
+ excludedClasses = Collections.unmodifiableSet(excludedClassesCopy);
+ excludedClassesCopy = null;
+
+ excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatternsCopy);
+ excludedPackageNamePatternsCopy = null;
+
+ excludedPackageNames = Collections.unmodifiableSet(excludedPackageNamesCopy);
+ excludedPackageNamesCopy = null;
+ }
+ }
+
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
Set<Class<?>> classes = new HashSet<>();
@@ -339,7 +370,7 @@ public class OgnlUtil {
* problems setting the properties
*/
public void setProperties(Map<String, ?> properties, Object o, boolean throwPropertyExceptions) {
- Map context = createDefaultContext(o, null);
+ Map context = createDefaultContext(o);
setProperties(properties, o, context, throwPropertyExceptions);
}
@@ -608,8 +639,8 @@ public class OgnlUtil {
return;
}
- final Map contextFrom = createDefaultContext(from, null);
- final Map contextTo = createDefaultContext(to, null);
+ final Map contextFrom = createDefaultContext(from);
+ final Map contextTo = createDefaultContext(to);
PropertyDescriptor[] fromPds;
PropertyDescriptor[] toPds;
@@ -719,7 +750,7 @@ public class OgnlUtil {
*/
public Map<String, Object> getBeanMap(final Object source) throws IntrospectionException, OgnlException {
Map<String, Object> beanMap = new HashMap<>();
- final Map sourceMap = createDefaultContext(source, null);
+ final Map sourceMap = createDefaultContext(source);
PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(source);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
final String propertyName = propertyDescriptor.getDisplayName();
diff --git a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
index 7e995f8..ff7e2d3 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
@@ -23,6 +23,7 @@ import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.PreResultListener;
+import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import org.apache.logging.log4j.LogManager;
@@ -145,18 +146,20 @@ public class DebuggingInterceptor extends AbstractInterceptor {
boolean devMode = devModeOverride != null ? devModeOverride : this.devMode;
if (devMode) {
final ActionContext ctx = ActionContext.getContext();
- String type = getParameter(DEBUG_PARAM);
- ctx.getParameters().remove(DEBUG_PARAM);
- if (XML_MODE.equals(type)) {
- inv.addPreResultListener(
+ ctx.getInstance(OgnlUtil.class).avoidAccessControl();;
+ try {
+ String type = getParameter(DEBUG_PARAM);
+ ctx.getParameters().remove(DEBUG_PARAM);
+ if (XML_MODE.equals(type)) {
+ inv.addPreResultListener(
new PreResultListener() {
public void beforeResult(ActionInvocation inv, String result) {
printContext();
}
});
- } else if (CONSOLE_MODE.equals(type)) {
- consoleEnabled = true;
- inv.addPreResultListener(
+ } else if (CONSOLE_MODE.equals(type)) {
+ consoleEnabled = true;
+ inv.addPreResultListener(
new PreResultListener() {
public void beforeResult(ActionInvocation inv, String actionResult) {
String xml = "";
@@ -183,64 +186,67 @@ public class DebuggingInterceptor extends AbstractInterceptor {
}
});
- } else if (COMMAND_MODE.equals(type)) {
- ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
- if (stack == null) {
- //allows it to be embedded on another page
- stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
- ctx.getSession().put(SESSION_KEY, stack);
- }
- String cmd = getParameter(EXPRESSION_PARAM);
+ } else if (COMMAND_MODE.equals(type)) {
+ ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
+ if (stack == null) {
+ //allows it to be embedded on another page
+ stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+ ctx.getSession().put(SESSION_KEY, stack);
+ }
+ String cmd = getParameter(EXPRESSION_PARAM);
- ServletActionContext.getRequest().setAttribute("decorator", "none");
- HttpServletResponse res = ServletActionContext.getResponse();
- res.setContentType("text/plain");
+ ServletActionContext.getRequest().setAttribute("decorator", "none");
+ HttpServletResponse res = ServletActionContext.getResponse();
+ res.setContentType("text/plain");
- try (PrintWriter writer =
- ServletActionContext.getResponse().getWriter()) {
- writer.print(stack.findValue(cmd));
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- cont = false;
- } else if (BROWSER_MODE.equals(type)) {
- actionOnly = true;
- inv.addPreResultListener(
- new PreResultListener() {
- public void beforeResult(ActionInvocation inv, String actionResult) {
- String rootObjectExpression = getParameter(OBJECT_PARAM);
- if (rootObjectExpression == null)
- rootObjectExpression = "#context";
- String decorate = getParameter(DECORATE_PARAM);
- ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
- Object rootObject = stack.findValue(rootObjectExpression);
-
- try (StringWriter writer = new StringWriter()) {
- ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
- htmlWriter.write(reflectionProvider, rootObject, rootObjectExpression);
- String html = writer.toString();
- writer.close();
-
- stack.set("debugHtml", html);
-
- //on the first request, response can be decorated
- //but we need plain text on the other ones
- if ("false".equals(decorate))
- ServletActionContext.getRequest().setAttribute("decorator", "none");
-
- FreemarkerResult result = new FreemarkerResult();
- result.setFreemarkerManager(freemarkerManager);
- result.setContentType("text/html");
- result.setLocation("/org/apache/struts2/interceptor/debugging/browser.ftl");
- result.execute(inv);
- } catch (Exception ex) {
- LOG.error("Unable to create debugging console", ex);
- }
+ try (PrintWriter writer =
+ ServletActionContext.getResponse().getWriter()) {
+ writer.print(stack.findValue(cmd));
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ cont = false;
+ } else if (BROWSER_MODE.equals(type)) {
+ actionOnly = true;
+ inv.addPreResultListener(
+ new PreResultListener() {
+ public void beforeResult(ActionInvocation inv, String actionResult) {
+ String rootObjectExpression = getParameter(OBJECT_PARAM);
+ if (rootObjectExpression == null)
+ rootObjectExpression = "top";
+ String decorate = getParameter(DECORATE_PARAM);
+ ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+ Object rootObject = stack.findValue(rootObjectExpression);
+
+ try (StringWriter writer = new StringWriter()) {
+ ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
+ htmlWriter.write(reflectionProvider, rootObject, rootObjectExpression);
+ String html = writer.toString();
+ writer.close();
+
+ stack.set("debugHtml", html);
+
+ //on the first request, response can be decorated
+ //but we need plain text on the other ones
+ if ("false".equals(decorate))
+ ServletActionContext.getRequest().setAttribute("decorator", "none");
+
+ FreemarkerResult result = new FreemarkerResult();
+ result.setFreemarkerManager(freemarkerManager);
+ result.setContentType("text/html");
+ result.setLocation("/org/apache/struts2/interceptor/debugging/browser.ftl");
+ result.execute(inv);
+ } catch (Exception ex) {
+ LOG.error("Unable to create debugging console", ex);
+ }
- }
- });
+ }
+ });
+ }
+ } finally {
+ ctx.getInstance(OgnlUtil.class).restoreAccessControl();
}
- }
+ }
if (cont) {
try {
if (actionOnly) {
diff --git a/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java b/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
index bad10b1..3374f73 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/debugging/ObjectToHTMLWriter.java
@@ -20,6 +20,8 @@ package org.apache.struts2.interceptor.debugging;
import com.opensymphony.xwork2.util.reflection.ReflectionException;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.beans.IntrospectionException;
import java.io.Writer;
@@ -33,6 +35,9 @@ import java.util.Set;
*
*/
class ObjectToHTMLWriter {
+
+ private static final Logger LOG = LogManager.getLogger(ObjectToHTMLWriter.class);
+
private PrettyPrintWriter prettyWriter;
ObjectToHTMLWriter(Writer writer) {
@@ -40,36 +45,43 @@ class ObjectToHTMLWriter {
this.prettyWriter.setEscape(false);
}
- @SuppressWarnings("unchecked")
public void write(ReflectionProvider reflectionProvider, Object root, String expr) throws IntrospectionException,
ReflectionException {
prettyWriter.startNode("table");
prettyWriter.addAttribute("class", "debugTable");
- if (root instanceof Map) {
- for (Object next : ((Map) root).entrySet()) {
- Map.Entry property = (Map.Entry) next;
+ if (root == null) {
+ LOG.info("Root is null");
+ writeProperty("root", null, expr);
+ } else if (root instanceof Map) {
+ LOG.info("Root is a Map");
+ for (Object next : ((Map<?, ?>) root).entrySet()) {
+ Map.Entry<?, ?> property = (Map.Entry<?, ?>) next;
String key = property.getKey().toString();
Object value = property.getValue();
writeProperty(key, value, expr);
}
} else if (root instanceof List) {
- List list = (List) root;
+ LOG.info("Root is a List");
+ List<?> list = (List<?>) root;
for (int i = 0; i < list.size(); i++) {
Object element = list.get(i);
writeProperty(String.valueOf(i), element, expr);
}
} else if (root instanceof Set) {
- Set set = (Set) root;
+ LOG.info("Root is a Set");
+ Set<?> set = (Set<?>) root;
for (Object next : set) {
writeProperty("", next, expr);
}
} else if (root.getClass().isArray()) {
+ LOG.info("Root is an Array");
Object[] objects = (Object[]) root;
for (int i = 0; i < objects.length; i++) {
writeProperty(String.valueOf(i), objects[i], expr);
}
} else {
+ LOG.info("Root is {}", root.getClass());
//print properties
Map<String, Object> properties = reflectionProvider.getBeanMap(root);
for (Map.Entry<String, Object> property : properties.entrySet()) {
@@ -99,9 +111,9 @@ class ObjectToHTMLWriter {
//value cell
prettyWriter.startNode("td");
if (value != null) {
+ LOG.info("Writing property [{}] as [{}]", name, value);
//if is is an empty collection or array, don't write a link
- if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass()
- .isArray() && ((Object[]) value).length == 0)) {
+ if (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass().isArray() && ((Object[]) value).length == 0)) {
prettyWriter.addAttribute("class", "emptyCollection");
prettyWriter.setValue("empty");
} else {
@@ -118,7 +130,7 @@ class ObjectToHTMLWriter {
prettyWriter.startNode("td");
if (value != null) {
prettyWriter.addAttribute("class", "typeColumn");
- Class clazz = value.getClass();
+ Class<?> clazz = value.getClass();
prettyWriter.setValue(clazz.getName());
} else {
prettyWriter.addAttribute("class", "nullValue");
@@ -135,7 +147,7 @@ class ObjectToHTMLWriter {
*/
private boolean isEmptyMap(Object value) {
try {
- return value instanceof Map && ((Map) value).isEmpty();
+ return value instanceof Map && ((Map<?, ?>) value).isEmpty();
} catch (Exception e) {
return true;
}
@@ -146,14 +158,14 @@ class ObjectToHTMLWriter {
*/
private boolean isEmptyCollection(Object value) {
try {
- return value instanceof Collection && ((Collection) value).isEmpty();
+ return value instanceof Collection && ((Collection<?>) value).isEmpty();
} catch (Exception e) {
return true;
}
}
private void writeValue(String name, Object value, String expr) {
- Class clazz = value.getClass();
+ Class<?> clazz = value.getClass();
if (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) ||
clazz.equals(String.class) || Boolean.class.equals(clazz)) {
prettyWriter.setValue(String.valueOf(value));