Author: b...@google.com Date: Wed Feb 4 08:23:36 2009 New Revision: 4622 Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java changes/bobv/elide_rpc_type_names_r4602/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java
Log: Obfuscate the name of the RPC service interface. Add type signature data to gwt.rpc file to ensure IncompatibleRemoteServiceExceptions are thrown when type signatures change. Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Wed Feb 4 08:23:36 2009 @@ -44,6 +44,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.google.gwt.user.server.rpc.SerializationPolicyLoader; +import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -52,7 +53,6 @@ import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -150,10 +150,11 @@ * Take the union of two type arrays, and then sort the results * alphabetically. */ - private static JType[] unionOfTypeArrays(JType[] types1, JType[] types2) { + private static JType[] unionOfTypeArrays(JType[]... types) { Set<JType> typesList = new HashSet<JType>(); - typesList.addAll(Arrays.asList(types1)); - typesList.addAll(Arrays.asList(types2)); + for (JType[] a : types) { + typesList.addAll(Arrays.asList(a)); + } JType[] serializableTypes = typesList.toArray(new JType[0]); Arrays.sort(serializableTypes, SerializableTypeOracleBuilder.JTYPE_COMPARATOR); @@ -161,6 +162,12 @@ } private boolean elideTypeNames; + + /** + * The possibly obfuscated type signatures used to represent a type. + */ + private Map<JType, String> typeSignatures; + private JClassType serviceIntf; { @@ -271,19 +278,23 @@ typesSentFromBrowser, typesSentToBrowser, context, SerializationUtils.getTypeSerializerQualifiedName(serviceIntf)); tsc.realize(logger); - Map<JType, String> obfuscatedTypeNames = elideTypeNames - ? tsc.getTypeSignatures() : Collections.<JType, String> emptyMap(); + + typeSignatures = new HashMap<JType, String>(tsc.getTypeSignatures()); + typeSignatures.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID); String serializationPolicyStrongName = writeSerializationPolicyFile(logger, context, typesSentFromBrowser, typesSentToBrowser); + String remoteServiceInterfaceName = elideTypeNames + ? TypeNameObfuscator.SERVICE_INTERFACE_ID + : TypeOracleMediator.computeBinaryClassName(serviceIntf); generateProxyFields(srcWriter, typesSentFromBrowser, - serializationPolicyStrongName); + serializationPolicyStrongName, remoteServiceInterfaceName); generateProxyContructor(javadocAnnotationDeprecationBranch, srcWriter); generateProxyMethods(srcWriter, typesSentFromBrowser, - syncMethToAsyncMethMap, obfuscatedTypeNames); + syncMethToAsyncMethMap); if (elideTypeNames) { generateStreamWriterOverride(srcWriter); @@ -319,12 +330,10 @@ */ private void generateProxyFields(SourceWriter srcWriter, SerializableTypeOracle serializableTypeOracle, - String serializationPolicyStrongName) { + String serializationPolicyStrongName, String remoteServiceInterfaceName) { // Initialize a field with binary name of the remote service interface srcWriter.println("private static final String REMOTE_SERVICE_INTERFACE_NAME = " - + (elideTypeNames ? "null" : ("\"" - + TypeOracleMediator.computeBinaryClassName(serviceIntf) + "\"")) - + ";"); + + "\"" + remoteServiceInterfaceName + "\";"); srcWriter.println("private static final String SERIALIZATION_POLICY =\"" + serializationPolicyStrongName + "\";"); String typeSerializerName = SerializationUtils.getTypeSerializerQualifiedName(serviceIntf); @@ -338,7 +347,7 @@ */ private void generateProxyMethod(SourceWriter w, SerializableTypeOracle serializableTypeOracle, JMethod syncMethod, - JMethod asyncMethod, Map<JType, String> obfuscatedTypeNames) { + JMethod asyncMethod) { w.println(); @@ -415,11 +424,13 @@ for (JParameter param : syncParams) { JType paramType = param.getType().getErasedType(); String typeName; - if (obfuscatedTypeNames.containsKey(paramType)) { - typeName = obfuscatedTypeNames.get(paramType); + if (typeSignatures.containsKey(paramType)) { + typeName = typeSignatures.get(paramType); } else { typeName = TypeOracleMediator.computeBinaryClassName(paramType); } + assert typeName != null : "Could not compute a type name for " + + paramType.getQualifiedSourceName(); w.println(streamWriterName + ".writeString(\"" + typeName + "\");"); } @@ -483,8 +494,7 @@ private void generateProxyMethods(SourceWriter w, SerializableTypeOracle serializableTypeOracle, - Map<JMethod, JMethod> syncMethToAsyncMethMap, - Map<JType, String> obfuscatedTypeNames) { + Map<JMethod, JMethod> syncMethToAsyncMethMap) { JMethod[] syncMethods = serviceIntf.getOverridableMethods(); for (JMethod syncMethod : syncMethods) { @@ -506,8 +516,7 @@ } } - generateProxyMethod(w, serializableTypeOracle, syncMethod, asyncMethod, - obfuscatedTypeNames); + generateProxyMethod(w, serializableTypeOracle, syncMethod, asyncMethod); } } @@ -603,11 +612,12 @@ ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(baos, SerializationPolicyLoader.SERIALIZATION_POLICY_FILE_ENCODING); + TypeOracle oracle = ctx.getTypeOracle(); PrintWriter pw = new PrintWriter(osw); JType[] serializableTypes = unionOfTypeArrays( serializationSto.getSerializableTypes(), - deserializationSto.getSerializableTypes()); + deserializationSto.getSerializableTypes(), new JType[] {serviceIntf}); for (int i = 0; i < serializableTypes.length; ++i) { JType type = serializableTypes[i]; @@ -620,7 +630,14 @@ pw.print(", " + Boolean.toString(serializationSto.isSerializable(type))); pw.print(", " + Boolean.toString(serializationSto.maybeInstantiated(type))); - pw.print(", " + Integer.toString(i, Character.MAX_RADIX)); + pw.print(", " + typeSignatures.get(type)); + + /* + * Include the serialization signature to bump the RPC file name if + * obfuscated identifiers are used. + */ + pw.print(", " + + SerializationUtils.getSerializationSignature(oracle, type)); pw.print('\n'); } Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java Wed Feb 4 08:23:36 2009 @@ -238,7 +238,8 @@ streamReader.prepareToRead(encodedRequest); // Read the name of the RemoteService interface - String serviceIntfName = streamReader.readString(); + String serviceIntfName = maybeDeobfuscate(streamReader, + streamReader.readString()); if (type != null) { if (!implementsInterface(type, serviceIntfName)) { @@ -273,20 +274,9 @@ Class<?>[] parameterTypes = new Class[paramCount]; for (int i = 0; i < parameterTypes.length; i++) { - String paramClassName = streamReader.readString(); - if (streamReader.hasFlags(AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES)) { - if (!(serializationPolicy instanceof TypeNameObfuscator)) { - throw new IncompatibleRemoteServiceException( - "RPC request was encoded with obfuscated type names, " - + "but the SerializationPolicy in use does not implement " - + TypeNameObfuscator.class.getName()); - } + String paramClassName = maybeDeobfuscate(streamReader, + streamReader.readString()); - String maybeNewTypeName = ((TypeNameObfuscator) serializationPolicy).getClassNameForTypeId(paramClassName); - if (maybeNewTypeName != null) { - paramClassName = maybeNewTypeName; - } - } try { parameterTypes[i] = getClassFromSerializedName(paramClassName, classLoader); @@ -821,6 +811,31 @@ } return false; + } + + /** + * Given a type identifier in the stream, attempt to deobfuscate it. Retuns + * the original identifier if deobfuscation is unnecessary or no mapping is + * known. + */ + private static String maybeDeobfuscate( + ServerSerializationStreamReader streamReader, String name) + throws SerializationException { + if (streamReader.hasFlags(AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES)) { + SerializationPolicy serializationPolicy = streamReader.getSerializationPolicy(); + if (!(serializationPolicy instanceof TypeNameObfuscator)) { + throw new IncompatibleRemoteServiceException( + "RPC request was encoded with obfuscated type names, " + + "but the SerializationPolicy in use does not implement " + + TypeNameObfuscator.class.getName()); + } + + String maybe = ((TypeNameObfuscator) serializationPolicy).getClassNameForTypeId(name); + if (maybe != null) { + return maybe; + } + } + return name; } /** Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/SerializationPolicyLoader.java Wed Feb 4 08:23:36 2009 @@ -16,6 +16,7 @@ package com.google.gwt.user.server.rpc; import com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy; +import com.google.gwt.user.server.rpc.impl.TypeNameObfuscator; import java.io.BufferedReader; import java.io.IOException; @@ -37,7 +38,7 @@ public static final String SERIALIZATION_POLICY_FILE_ENCODING = "UTF-8"; private static final String FORMAT_ERROR_MESSAGE = "Expected: className, " - + "[true | false], [true | false], [true | false], [true | false], typeId"; + + "[true | false], [true | false], [true | false], [true | false], typeId, signature"; /** * Returns the serialization policy file name from the from the serialization @@ -115,7 +116,7 @@ if (line.length() > 0) { String[] components = line.split(","); - if (components.length != 2 && components.length != 6) { + if (components.length != 2 && components.length != 7) { throw new ParseException(FORMAT_ERROR_MESSAGE, lineNum); } @@ -146,10 +147,11 @@ instantDeser = Boolean.valueOf(components[idx++]); typeId = components[idx++]; - if (!fieldSer && !fieldDeser) { + if (!fieldSer && !fieldDeser + && !TypeNameObfuscator.SERVICE_INTERFACE_ID.equals(typeId)) { throw new ParseException("Type " + binaryTypeName - + " is neither field serializable nor field deserializable", - lineNum); + + " is neither field serializable, field deserializable " + + "nor the service interface", lineNum); } } Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/impl/TypeNameObfuscator.java Wed Feb 4 08:23:36 2009 @@ -21,10 +21,19 @@ * This is a private interface that allows ProxyCreator to provide obfuscated * type names to the server components via {...@link StandardSerializationPolicy}. * <p> - * The particulars of the implementation are deeply tied to the specifiecs of - * the RPC wire format and the code generated by TypeSerializerCreator. + * The particulars of the implementation are deeply tied to the specifics of the + * RPC wire format and the code generated by TypeSerializerCreator. + * <p> + * This interface is not public in order to allow the API to be switched from + * Strings to ints in a future revision. */ public interface TypeNameObfuscator { + /** + * A reserved ID for specifying the identifier for the service interface + * itself. + */ + String SERVICE_INTERFACE_ID = "_"; + /* * TODO: Replace strings with integral constants once the RPC whitelist can be * given as a hard requirement for deploying GWT-RPC. Modified: changes/bobv/elide_rpc_type_names_r4602/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/test/com/google/gwt/user/server/rpc/SerializationPolicyLoaderTest.java Wed Feb 4 08:23:36 2009 @@ -40,6 +40,9 @@ static class B { } + static class I { + } + private static final String OLD_VALID_POLICY_FILE_CONTENTS = A.class.getName() + ", true"; @@ -49,8 +52,10 @@ private static final String POLICY_FILE_TRIGGERS_CLASSNOTFOUND = "C,false"; private static final String VALID_POLICY_FILE_CONTENTS = A.class.getName() - + ", true, true, false, false, a\n" + B.class.getName() - + ", false, false, true, false, b\n"; + + ", true, true, false, false, a, 1234\n" + B.class.getName() + + ", false, false, true, false, b, 5678\n" + I.class.getName() + + ", false, false, false, false, " + + TypeNameObfuscator.SERVICE_INTERFACE_ID + ", 999\n"; public static InputStream getInputStreamFromString(String content) throws UnsupportedEncodingException { @@ -90,6 +95,10 @@ assertEquals(A.class.getName(), ob.getClassNameForTypeId("a")); assertEquals("b", ob.getTypeIdForClass(B.class)); assertEquals(B.class.getName(), ob.getClassNameForTypeId("b")); + assertEquals(TypeNameObfuscator.SERVICE_INTERFACE_ID, + ob.getTypeIdForClass(I.class)); + assertEquals(I.class.getName(), + ob.getClassNameForTypeId(TypeNameObfuscator.SERVICE_INTERFACE_ID)); } /** --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---