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 <lukaszlen...@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));