Implement RPC blacklists. Review by: scottb,spoon git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5324 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardConfigurationProperty.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardConfigurationProperty.java index ef29748..d035406 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardConfigurationProperty.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardConfigurationProperty.java
@@ -33,8 +33,12 @@ name = p.getName(); values = p.getValues(); - if (values == null || values.size() == 0) { - throw new IllegalArgumentException("values is null or empty"); + if (values == null) { + throw new IllegalArgumentException("values is null"); + } + if (!p.allowsMultipleValues() && values.size() != 1) { + throw new IllegalArgumentException( + "p is single-valued but values.size != 1"); } }
diff --git a/user/src/com/google/gwt/user/RemoteService.gwt.xml b/user/src/com/google/gwt/user/RemoteService.gwt.xml index 31baf7c..7e89fc1 100644 --- a/user/src/com/google/gwt/user/RemoteService.gwt.xml +++ b/user/src/com/google/gwt/user/RemoteService.gwt.xml
@@ -35,6 +35,17 @@ --> <define-configuration-property name="gwt.elideTypeNamesFromRPC" is-multi-valued="false" /> <set-configuration-property name="gwt.elideTypeNamesFromRPC" value="false" /> + + <!-- + Contains regular expressions, optionally prefixed with '+' or '-'. + Each type being considered for serialization is tested against the + list of expressions in order, and if there is a match it is added to the + blacklist (if the prefix is '-' or no prefix is present), or removed (if + the prefix is '+'). If multiple entries in the list match a supplied + class, then the last one 'wins.' For generic types, the regular + expression is applied to just the base class's fully qualified name. + --> + <define-configuration-property name="rpc.blacklist" is-multi-valued="true" /> <generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator"> <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
diff --git a/user/src/com/google/gwt/user/rebind/rpc/BlacklistTypeFilter.java b/user/src/com/google/gwt/user/rebind/rpc/BlacklistTypeFilter.java new file mode 100644 index 0000000..239d1f5 --- /dev/null +++ b/user/src/com/google/gwt/user/rebind/rpc/BlacklistTypeFilter.java
@@ -0,0 +1,140 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.user.rebind.rpc; + +import com.google.gwt.core.ext.BadPropertyValueException; +import com.google.gwt.core.ext.ConfigurationProperty; +import com.google.gwt.core.ext.PropertyOracle; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JRealClassType; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +class BlacklistTypeFilter implements TypeFilter { + + private List<Boolean> includeType; + private TreeLogger logger; + private List<Pattern> typePatterns; + private List<String> values; + + public BlacklistTypeFilter(TreeLogger logger, PropertyOracle propertyOracle) + throws UnableToCompleteException { + this.logger = logger.branch(TreeLogger.DEBUG, + "Analyzing RPC blacklist information"); + try { + ConfigurationProperty prop + = propertyOracle.getConfigurationProperty("rpc.blacklist"); + + values = prop.getValues(); + int size = values.size(); + typePatterns = new ArrayList<Pattern>(size); + includeType = new ArrayList<Boolean>(size); + + // TODO investigate grouping multiple patterns into a single regex + for (String regex : values) { + // Patterns that don't start with [+-] are considered to be [-] + boolean include = false; + // Ignore empty regexes + if (regex.length() == 0) { + logger.log(TreeLogger.ERROR, "Got empty RPC blacklist entry"); + throw new UnableToCompleteException(); + } + char c = regex.charAt(0); + if (c == '+' || c == '-') { + regex = regex.substring(1); // skip initial character + include = (c == '+'); + } + try { + Pattern p = Pattern.compile(regex); + typePatterns.add(p); + includeType.add(include); + + logger.log(TreeLogger.DEBUG, + "Got RPC blacklist entry '" + regex + "'"); + } catch (PatternSyntaxException e) { + logger.log(TreeLogger.ERROR, + "Got malformed RPC blacklist entry '" + regex + "'"); + throw new UnableToCompleteException(); + } + } + } catch (BadPropertyValueException e) { + logger.log(TreeLogger.DEBUG, "No RPC blacklist entries present"); + } + } + + public String getName() { + return "BlacklistTypeFilter"; + } + + + public boolean isAllowed(JClassType type) { + String name = getBaseTypeName(type); + // For types not handled by getBaseTypeName just return true. + if (name == null) { + return true; + } + + // Process patterns in reverse order for early exit + int size = typePatterns.size(); + for (int idx = size - 1; idx >= 0; idx--) { + logger.log(TreeLogger.DEBUG, "Considering RPC rule " + values.get(idx) + + " for type " + name); + boolean include = includeType.get(idx); + Pattern pattern = typePatterns.get(idx); + if (pattern.matcher(name).matches()) { + if (include) { + logger.log(TreeLogger.DEBUG, "Whitelisting type " + name + + " according to rule " + values.get(idx)); + return true; + } else { + logger.log(TreeLogger.DEBUG, "Blacklisting type " + name + + " according to rule " + values.get(idx)); + return false; + } + } + } + + // Type does not match any pattern, pass it through + return true; + } + + /** + * Returns a simple qualified name for simple types, including classes and + * interfaces, parameterized, and raw types. Null is returned for other types + * such as arrays and type parameters (e.g., 'E' in java.util.List<E>) because + * filtering is meaningless for such types. + */ + private String getBaseTypeName(JClassType type) { + JClassType baseType = null; + + if (type instanceof JRealClassType) { + baseType = type; + } else if (type.isParameterized() != null) { + baseType = type.isParameterized().getBaseType(); + } else if (type.isRawType() != null) { + baseType = type.isRawType(); + } + + return baseType == null ? null : baseType.getQualifiedSourceName(); + } +} +
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java index 84a06bb..346e2cd 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -234,11 +234,17 @@ final PropertyOracle propertyOracle = context.getPropertyOracle(); + // Load the blacklist/whitelist + TypeFilter blacklistTypeFilter = new BlacklistTypeFilter(logger, propertyOracle); + // Determine the set of serializable types SerializableTypeOracleBuilder typesSentFromBrowserBuilder = new SerializableTypeOracleBuilder( logger, propertyOracle, typeOracle); + typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter); SerializableTypeOracleBuilder typesSentToBrowserBuilder = new SerializableTypeOracleBuilder( logger, propertyOracle, typeOracle); + typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter); + try { addRequiredRoots(logger, typeOracle, typesSentFromBrowserBuilder); addRequiredRoots(logger, typeOracle, typesSentToBrowserBuilder); @@ -267,9 +273,25 @@ // output. OutputStream pathInfo = context.tryCreateResource(logger, serviceIntf.getQualifiedSourceName() + ".rpc.log"); + PrintWriter writer = new PrintWriter(pathInfo); + typesSentFromBrowserBuilder.setLogOutputStream(pathInfo); - SerializableTypeOracle typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger); - SerializableTypeOracle typesSentToBrowser = typesSentToBrowserBuilder.build(logger); + typesSentToBrowserBuilder.setLogOutputStream(pathInfo); + + writer.write("====================================\n"); + writer.write("Types potentially sent from browser:\n"); + writer.write("====================================\n\n"); + writer.flush(); + SerializableTypeOracle typesSentFromBrowser + = typesSentFromBrowserBuilder.build(logger); + + writer.write("===================================\n"); + writer.write("Types potentially sent from server:\n"); + writer.write("===================================\n\n"); + writer.flush(); + SerializableTypeOracle typesSentToBrowser + = typesSentToBrowserBuilder.build(logger); + if (pathInfo != null) { context.commitResource(logger, pathInfo).setPrivate(true); }