summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2007-05-10 05:09:05 +0000
committerMichi Henning <michi@zeroc.com>2007-05-10 05:09:05 +0000
commit9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c (patch)
tree7b1fecab8ebe32a9e2e8c3c32a90e9643a4bebf7
parentFixed misplaced assignment to _rawBytes. (diff)
downloadice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.tar.bz2
ice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.tar.xz
ice-9cb97bc06da9fdf7e63d167ea5855ad5d5fbfe9c.zip
Bug 1022.
-rw-r--r--java/CHANGES25
-rw-r--r--java/src/IceInternal/EndpointFactoryManager.java43
-rw-r--r--java/src/IceInternal/UnknownEndpointI.java100
-rw-r--r--java/src/IceUtil/Base64.java274
-rw-r--r--java/test/Ice/proxy/AllTests.java149
-rw-r--r--java/test/Ice/proxy/MyDerivedClassI.java6
-rw-r--r--java/test/Ice/proxy/Test.ice3
-rw-r--r--java/test/Ice/proxyAMD/MyDerivedClassI.java8
-rw-r--r--java/test/Ice/proxyAMD/TestAMD.ice1
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);
};
};