diff options
author | Michi Henning <michi@zeroc.com> | 2007-05-10 05:09:05 +0000 |
---|---|---|
committer | Michi Henning <michi@zeroc.com> | 2007-05-10 05:09:05 +0000 |
commit | 9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c (patch) | |
tree | 7b1fecab8ebe32a9e2e8c3c32a90e9643a4bebf7 | |
parent | Fixed misplaced assignment to _rawBytes. (diff) | |
download | ice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.tar.bz2 ice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.tar.xz ice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.zip |
Bug 1022.
-rw-r--r-- | java/CHANGES | 25 | ||||
-rw-r--r-- | java/src/IceInternal/EndpointFactoryManager.java | 43 | ||||
-rw-r--r-- | java/src/IceInternal/UnknownEndpointI.java | 100 | ||||
-rw-r--r-- | java/src/IceUtil/Base64.java | 274 | ||||
-rw-r--r-- | java/test/Ice/proxy/AllTests.java | 149 | ||||
-rw-r--r-- | java/test/Ice/proxy/MyDerivedClassI.java | 6 | ||||
-rw-r--r-- | java/test/Ice/proxy/Test.ice | 3 | ||||
-rw-r--r-- | java/test/Ice/proxyAMD/MyDerivedClassI.java | 8 | ||||
-rw-r--r-- | java/test/Ice/proxyAMD/TestAMD.ice | 1 |
9 files changed, 603 insertions, 6 deletions
diff --git a/java/CHANGES b/java/CHANGES index ed0d6336ec5..b629078391b 100644 --- a/java/CHANGES +++ b/java/CHANGES @@ -1,6 +1,31 @@ Changes since version 3.2.0 --------------------------- +- Added support for opaque endpoints. For example: + + opaque -t 2 -v CTEyNy4wLjAuMREnAAD/////AA== + + This is the same as: + + ssl -h 127.0.0.1 -p 10001 + + The "opaque" protocol identifier indicates an unknown protocol. + Both the -t and the -v option must be present: + + -t <num>: Indicates the protocol type (TCP = 1, SSL = 2, UDP = 3). + + -v <base64>: Provides the value of the opaque endpoint. The option + argument is the marshaled representation of the endpoint + (including the endpoint's enclosing encapsulation) in + base64 encoding. + + This syntax is useful if, for example, a client that has the SSL + plugin configured sends a proxy with an SSL endpoint to a server + without the SSL plugin. Prior to this version, the server would + drop the unknown SSL endpoint when it stringified the proxy. + As of this version, the server preserves the endpoint and, when the server + stringifies a proxy containing an unknown endpoint, it uses the above opaque syntax. + - Trailing characters past the adapter id in a stringified proxy will now raise a ProxyParseException. diff --git a/java/src/IceInternal/EndpointFactoryManager.java b/java/src/IceInternal/EndpointFactoryManager.java index b2d341b04ba..3ddbbe42b60 100644 --- a/java/src/IceInternal/EndpointFactoryManager.java +++ b/java/src/IceInternal/EndpointFactoryManager.java @@ -73,7 +73,50 @@ public final class EndpointFactoryManager if(f.protocol().equals(protocol)) { return f.create(s.substring(m.end())); + + // Code below left in place for debugging. + + /* + EndpointI e = f.create(s.substring(m.end())); + BasicStream bs = new BasicStream(_instance, true); + e.streamWrite(bs); + java.nio.ByteBuffer buf = bs.prepareRead(); + buf.position(0); + short type = bs.readShort(); + EndpointI ue = new IceInternal.UnknownEndpointI(type, bs); + System.err.println("Normal: " + e); + System.err.println("Opaque: " + ue); + return e; + */ + } + } + + // + // If the stringified endpoint is opaque, create an unknown endpoint, + // then see whether the type matches one of the known endpoints. + // + if(protocol.equals("opaque")) + { + EndpointI ue = new UnknownEndpointI(s.substring(m.end())); + for(int i = 0; i < _factories.size(); i++) + { + EndpointFactory f = (EndpointFactory)_factories.get(i); + if(f.type() == ue.type()) + { + // + // Make a temporary stream, write the opaque endpoint data into the stream, + // and ask the factory to read the endpoint data from that stream to create + // the actual endpoint. + // + BasicStream bs = new BasicStream(_instance, true); + ue.streamWrite(bs); + java.nio.ByteBuffer buf = bs.prepareRead(); + buf.position(0); + short type = bs.readShort(); + return f.read(bs); + } } + return ue; // Endpoint is opaque, but we don't have a factory for its type. } return null; diff --git a/java/src/IceInternal/UnknownEndpointI.java b/java/src/IceInternal/UnknownEndpointI.java index 0b9b4271715..c8621132123 100644 --- a/java/src/IceInternal/UnknownEndpointI.java +++ b/java/src/IceInternal/UnknownEndpointI.java @@ -12,9 +12,96 @@ package IceInternal; final class UnknownEndpointI extends EndpointI { public + UnknownEndpointI(String str) + { + int topt = 0; + int vopt = 0; + + String[] arr = str.split("[ \t\n\r]+"); + int i = 0; + while(i < arr.length) + { + if(arr[i].length() == 0) + { + i++; + continue; + } + + String option = arr[i++]; + if(option.length() != 2 || option.charAt(0) != '-') + { + throw new Ice.EndpointParseException("opaque " + str); + } + + String argument = null; + if(i < arr.length && arr[i].charAt(0) != '-') + { + argument = arr[i++]; + } + + switch(option.charAt(1)) + { + case 't': + { + if(argument == null) + { + throw new Ice.EndpointParseException("opaque " + str); + } + + int t; + try + { + t = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("opaque " + str); + } + + if(t < 0 || t > 65535) + { + throw new Ice.EndpointParseException("opaque " + str); + } + + _type = (short)t; + ++topt; + break; + } + + case 'v': + { + if(argument == null) + { + throw new Ice.EndpointParseException("opaque " + str); + } + for(int j = 0; j < argument.length(); ++j) + { + if(!IceUtil.Base64.isBase64(argument.charAt(j))) + { + throw new Ice.EndpointParseException("opaque " + str); + } + } + _rawBytes = IceUtil.Base64.decode(argument); + ++vopt; + break; + } + + default: + { + throw new Ice.EndpointParseException("opaque " + str); + } + } + } + + if(topt != 1 || vopt != 1) + { + throw new Ice.EndpointParseException("opaque " + str); + } + } + + public UnknownEndpointI(short type, BasicStream s) { - _instance = s.instance(); _type = type; s.startReadEncaps(); int sz = s.getReadEncapsSize(); @@ -41,7 +128,8 @@ final class UnknownEndpointI extends EndpointI public String _toString() { - return ""; + String val = IceUtil.Base64.encode(_rawBytes); + return "opaque -t " + _type + " -v " + val; } // @@ -187,8 +275,11 @@ final class UnknownEndpointI extends EndpointI public java.util.ArrayList expand(boolean server) { - assert(false); - return null; + + java.util.ArrayList endps = new java.util.ArrayList(); + calcHashValue(); + endps.add(this); + return endps; } // @@ -299,7 +390,6 @@ final class UnknownEndpointI extends EndpointI } } - private Instance _instance; private short _type; private byte[] _rawBytes; private int _hashCode; diff --git a/java/src/IceUtil/Base64.java b/java/src/IceUtil/Base64.java new file mode 100644 index 00000000000..da56f58cf4a --- /dev/null +++ b/java/src/IceUtil/Base64.java @@ -0,0 +1,274 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtil; + +public class Base64 +{ + +public static String +encode(byte[] plainSeq) +{ + if(plainSeq == null || plainSeq.length == 0) + { + return ""; + } + + StringBuffer retval = new StringBuffer(); + int base64Bytes = (((plainSeq.length * 4) / 3) + 1); + int newlineBytes = (((base64Bytes * 2) / 76) + 1); + int totalBytes = base64Bytes + newlineBytes; + + retval.ensureCapacity(totalBytes); + + int by1; + int by2; + int by3; + int by4; + int by5; + int by6; + int by7; + + for(int i = 0; i < plainSeq.length; i += 3) + { + by1 = plainSeq[i] & 0xff; + by2 = 0; + by3 = 0; + + if((i + 1) < plainSeq.length) + { + by2 = plainSeq[i+1] & 0xff; + } + + if((i + 2) < plainSeq.length) + { + by3 = plainSeq[i+2] & 0xff; + } + + by4 = (by1 >> 2) & 0xff; + by5 = (((by1 & 0x3) << 4) | (by2 >> 4)) & 0xff; + by6 = (((by2 & 0xf) << 2) | (by3 >> 6)) & 0xff; + by7 = by3 & 0x3f; + + retval.append(encode((byte)by4)); + retval.append(encode((byte)by5)); + + if((i + 1) < plainSeq.length) + { + retval.append(encode((byte)by6)); + } + else + { + retval.append('='); + } + + if((i + 2) < plainSeq.length) + { + retval.append(encode((byte)by7)); + } + else + { + retval.append('='); + } + } + + StringBuffer outString = new StringBuffer(); + outString.ensureCapacity(totalBytes); + int iter = 0; + + while((retval.length() - iter) > 76) + { + outString.append(retval.substring(iter, 76)); + outString.append("\r\n"); + iter += 76; + } + + outString.append(retval.substring(iter)); + + return outString.toString(); +} + +public static byte[] +decode(String str) +{ + StringBuffer newStr = new StringBuffer(); + + newStr.ensureCapacity(str.length()); + + for(int j = 0; j < str.length(); j++) + { + char c = str.charAt(j); + if(isBase64(c)) + { + newStr.append(c); + } + } + + if(newStr.length() == 0) + { + return null; + } + + // Note: This is how we were previously computing the size of the return + // sequence. The method below is more efficient (and correct). + // size_t lines = str.size() / 78; + // size_t totalBytes = (lines * 76) + (((str.size() - (lines * 78)) * 3) / 4); + + // Figure out how long the final sequence is going to be. + int totalBytes = (newStr.length() * 3 / 4) + 1; + + java.nio.ByteBuffer retval = java.nio.ByteBuffer.allocate(totalBytes); + + int by1; + int by2; + int by3; + int by4; + + char c1, c2, c3, c4; + + int pos = 0; + for(int i = 0; i < newStr.length(); i += 4) + { + c1 = 'A'; + c2 = 'A'; + c3 = 'A'; + c4 = 'A'; + + c1 = newStr.charAt(i); + + if((i + 1) < newStr.length()) + { + c2 = newStr.charAt(i + 1); + } + + if((i + 2) < newStr.length()) + { + c3 = newStr.charAt(i + 2); + } + + if((i + 3) < newStr.length()) + { + c4 = newStr.charAt(i + 3); + } + + by1 = decode(c1) & 0xff; + by2 = decode(c2) & 0xff; + by3 = decode(c3) & 0xff; + by4 = decode(c4) & 0xff; + + retval.put((byte)((by1 << 2) | (by2 >> 4))); + ++pos; + + if(c3 != '=') + { + retval.put((byte)(((by2 & 0xf) << 4) | (by3 >> 2))); + ++pos; + } + + if(c4 != '=') + { + retval.put((byte)(((by3 & 0x3) << 6) | by4)); + ++pos; + } + } + + byte[] arr = new byte[pos]; + System.arraycopy(retval.array(), 0, arr, 0, pos); + return arr; +} + +public static boolean +isBase64(char c) +{ + if(c >= 'A' && c <= 'Z') + { + return true; + } + + if(c >= 'a' && c <= 'z') + { + return true; + } + + if(c >= '0' && c <= '9') + { + return true; + } + + if(c == '+') + { + return true; + } + + if(c == '/') + { + return true; + } + + if(c == '=') + { + return true; + } + + return false; +} + +private static char +encode(byte uc) +{ + if(uc < 26) + { + return (char)('A' + uc); + } + + if(uc < 52) + { + return (char)('a' + (uc - 26)); + } + + if(uc < 62) + { + return (char)('0' + (uc - 52)); + } + + if(uc == 62) + { + return '+'; + } + + return '/'; +} + +private static byte +decode(char c) +{ + if(c >= 'A' && c <= 'Z') + { + return (byte)(c - 'A'); + } + + if(c >= 'a' && c <= 'z') + { + return (byte)(c - 'a' + 26); + } + + if(c >= '0' && c <= '9') + { + return (byte)(c - '0' + 52); + } + + if(c == '+') + { + return 62; + } + + return 63; +} + +} diff --git a/java/test/Ice/proxy/AllTests.java b/java/test/Ice/proxy/AllTests.java index 5b6b39c1759..95bfc475ec9 100644 --- a/java/test/Ice/proxy/AllTests.java +++ b/java/test/Ice/proxy/AllTests.java @@ -424,6 +424,155 @@ public class AllTests test(c.equals(c2)); System.out.println("ok"); + System.out.print("testing opaque endpoints... "); + System.out.flush(); + + try + { + // Invalid -x option + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 99 -v abc -x abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Missing -t and -v + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Repeated -t + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 1 -t 1 -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Repeated -v + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 1 -v abc -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Missing -t + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Missing -v + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 1"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Missing arg for -t + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Missing arg for -v + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 1 -v"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Not a number for -t + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t x -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // < 0 for -t + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t -1 -v abc"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + try + { + // Invalid char for -v + Ice.ObjectPrx p = communicator.stringToProxy("id:opaque -t 99 -v x?c"); + test(false); + } + catch(Ice.EndpointParseException ex) + { + } + + // Legal TCP endpoint expressed as opaque endpoint + Ice.ObjectPrx p1 = communicator.stringToProxy("test:opaque -t 1 -v AOouAAAQJwAAAA=="); + String pstr = communicator.proxyToString(p1); + test(pstr.equals("test -t:tcp -h 127.0.0.1 -p 12010 -t 10000")); + + // Working? + p1.ice_ping(); + + // Two legal TCP endpoints expressed as opaque endpoints + p1 = communicator.stringToProxy("test:opaque -t 1 -v CTEyNy4wLjAuMeouAAAQJwAAAA==:opaque -t 1 -v CTEyNy4wLjAuMusuAAAQJwAAAA=="); + pstr = communicator.proxyToString(p1); + test(pstr.equals("test -t:tcp -h 127.0.0.1 -p 12010 -t 10000:tcp -h 127.0.0.2 -p 12011 -t 10000")); + + // Test that an SSL endpoint and a nonsense endpoint get written back out as an opaque endpoint. + p1 = communicator.stringToProxy("test:opaque -t 2 -v CTEyNy4wLjAuMREnAAD/////AA==:opaque -t 99 -v abch"); + pstr = communicator.proxyToString(p1); + test(pstr.equals("test -t:opaque -t 2 -v CTEyNy4wLjAuMREnAAD/////AA==:opaque -t 99 -v abch")); + + // Try to invoke on the SSL endpoint to verify that we get a NoEndpointException. + try + { + p1.ice_ping(); + test(false); + } + catch(Ice.NoEndpointException ex) + { + } + + // Test that the proxy with an SSL endpoint and a nonsense endpoint (which the server doesn't understand either) + // can be sent over the wire and returned by the server without losing the opaque endpoints. + Ice.ObjectPrx p2 = derived.echo(p1); + pstr = communicator.proxyToString(p2); + test(pstr.equals("test -t:opaque -t 2 -v CTEyNy4wLjAuMREnAAD/////AA==:opaque -t 99 -v abch")); + + System.out.println("ok"); + return cl; } } diff --git a/java/test/Ice/proxy/MyDerivedClassI.java b/java/test/Ice/proxy/MyDerivedClassI.java index db4084975cf..7ee5de382bf 100644 --- a/java/test/Ice/proxy/MyDerivedClassI.java +++ b/java/test/Ice/proxy/MyDerivedClassI.java @@ -14,6 +14,12 @@ public final class MyDerivedClassI extends Test.MyDerivedClass { } + public Ice.ObjectPrx + echo(Ice.ObjectPrx obj, Ice.Current c) + { + return obj; + } + public void shutdown(Ice.Current c) { diff --git a/java/test/Ice/proxy/Test.ice b/java/test/Ice/proxy/Test.ice index ee3b6bdb724..75b0b29d993 100644 --- a/java/test/Ice/proxy/Test.ice +++ b/java/test/Ice/proxy/Test.ice @@ -22,8 +22,9 @@ module Test Ice::Context getContext(); }; -["ami"] class MyDerivedClass extends MyClass +class MyDerivedClass extends MyClass { + Object* echo(Object* obj); }; }; diff --git a/java/test/Ice/proxyAMD/MyDerivedClassI.java b/java/test/Ice/proxyAMD/MyDerivedClassI.java index bd1a1314abc..20d45b4aaed 100644 --- a/java/test/Ice/proxyAMD/MyDerivedClassI.java +++ b/java/test/Ice/proxyAMD/MyDerivedClassI.java @@ -15,6 +15,14 @@ public final class MyDerivedClassI extends Test.MyDerivedClass } public void + echo_async(Test.AMD_MyDerivedClass_echo cb, + Ice.ObjectPrx obj, + Ice.Current c) + { + cb.ice_response(obj); + } + + public void shutdown_async(Test.AMD_MyClass_shutdown cb, Ice.Current c) { diff --git a/java/test/Ice/proxyAMD/TestAMD.ice b/java/test/Ice/proxyAMD/TestAMD.ice index 6ffe76a4597..f75c96d6d46 100644 --- a/java/test/Ice/proxyAMD/TestAMD.ice +++ b/java/test/Ice/proxyAMD/TestAMD.ice @@ -24,6 +24,7 @@ module Test ["ami", "amd"] class MyDerivedClass extends MyClass { + Object* echo(Object* obj); }; }; |