Safari2/3 RPC quoting fixes.
Patch by: jat
Review by: jgw (desk review)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.5@3767 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
index ed1adea..2b695c4 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
@@ -57,13 +57,24 @@
private static native JavaScriptObject getQuotingRegex() /*-{
// "|" = AbstractSerializationStream.RPC_SEPARATOR_CHAR
var ua = navigator.userAgent.toLowerCase();
+ var webkitregex = /webkit\/([\d]+)/;
+ var webkit = 0;
+ var result = webkitregex.exec(ua);
+ if (result) {
+ webkit = parseInt(result[1]);
+ }
if (ua.indexOf("android") != -1) {
// initial version of Android WebKit has a double-encoding bug for UTF8,
- // so we have to encode every non-ASCII character. Later builds can
- // use \u0300 instead of \u0080, and hopefully by the time Android
- // supports non-Latin input it will be fully fixed.
+ // so we have to encode every non-ASCII character.
// TODO(jat): revisit when this bug is fixed in Android
return /[\u0000\|\\\u0080-\uFFFF]/g;
+ } else if (webkit < 522) {
+ // Safari 2 doesn't handle \\uXXXX in regexes
+ // TODO(jat): should iPhone be treated specially?
+ return /[\x00\|\\]/g;
+ } else if (webkit > 0) {
+ // other WebKit-based browsers need some additional quoting
+ return /[\u0000\|\\\u0300-\u036F\u0590-\u05FF\uD800-\uFFFF]/g;
} else {
return /[\u0000\|\\\uD800-\uFFFF]/g;
}
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
index 492dbb7..92e1cd3 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
@@ -77,43 +77,50 @@
private enum ValueReader {
BOOLEAN {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readBoolean();
}
},
BYTE {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readByte();
}
},
CHAR {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readChar();
}
},
DOUBLE {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readDouble();
}
},
FLOAT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readFloat();
}
},
INT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readInt();
}
},
LONG {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readLong();
}
},
@@ -126,13 +133,15 @@
},
SHORT {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readShort();
}
},
STRING {
@Override
- Object readValue(ServerSerializationStreamReader stream) {
+ Object readValue(ServerSerializationStreamReader stream)
+ throws SerializationException {
return stream.readString();
}
};
@@ -323,6 +332,7 @@
private final ArrayList<String> tokenList = new ArrayList<String>();
private int tokenListIndex;
+
{
CLASS_TO_VECTOR_READER.put(boolean[].class, VectorReader.BOOLEAN_VECTOR);
CLASS_TO_VECTOR_READER.put(byte[].class, VectorReader.BYTE_VECTOR);
@@ -426,42 +436,42 @@
}
}
- public boolean readBoolean() {
+ public boolean readBoolean() throws SerializationException {
return !extract().equals("0");
}
- public byte readByte() {
+ public byte readByte() throws SerializationException {
return Byte.parseByte(extract());
}
- public char readChar() {
+ public char readChar() throws SerializationException {
// just use an int, it's more foolproof
return (char) Integer.parseInt(extract());
}
- public double readDouble() {
+ public double readDouble() throws SerializationException {
return Double.parseDouble(extract());
}
- public float readFloat() {
+ public float readFloat() throws SerializationException {
return (float) Double.parseDouble(extract());
}
- public int readInt() {
+ public int readInt() throws SerializationException {
return Integer.parseInt(extract());
}
- public long readLong() {
+ public long readLong() throws SerializationException {
// Keep synchronized with LongLib. The wire format are the two component
// parts of the double in the client code.
return (long) readDouble() + (long) readDouble();
}
- public short readShort() {
+ public short readShort() throws SerializationException {
return Short.parseShort(extract());
}
- public String readString() {
+ public String readString() throws SerializationException {
return getString(readInt());
}
@@ -675,14 +685,18 @@
throw new NoSuchMethodException("deserialize");
}
- private String extract() {
- return tokenList.get(tokenListIndex++);
+ private String extract() throws SerializationException {
+ try {
+ return tokenList.get(tokenListIndex++);
+ } catch (IndexOutOfBoundsException e) {
+ throw new SerializationException("Too few tokens in RPC request", e);
+ }
}
private Object instantiate(Class<?> customSerializer, Class<?> instanceClass)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException,
- NoSuchMethodException {
+ NoSuchMethodException, SerializationException {
if (customSerializer != null) {
for (Method method : customSerializer.getMethods()) {
if ("instantiate".equals(method.getName())) {
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
index e000493..f45777e 100644
--- a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
@@ -60,6 +60,28 @@
return buf.toString();
}
+ /*
+ * Copied from HistoryTest.
+ */
+ private static native boolean isSafari2() /*-{
+ var exp = / AppleWebKit\/([\d]+)/;
+ var result = exp.exec(navigator.userAgent);
+ if (result) {
+ // The standard history implementation works fine on WebKit >= 522
+ // (Safari 3 beta).
+ if (parseInt(result[1]) >= 522) {
+ return false;
+ }
+ }
+
+ // The standard history implementation works just fine on the iPhone, which
+ // unfortunately reports itself as WebKit/420+.
+ if (navigator.userAgent.indexOf('iPhone') != -1) {
+ return false;
+ }
+
+ return true;
+ }-*/;
/**
* Verifies that the supplied string includes the requested code points.
*
@@ -113,6 +135,10 @@
* server for verification. This ensures that client->server string escaping
* properly handles all BMP characters.
*
+ * Unpaired or improperly paired surrogates are not tested here, as some
+ * browsers refuse to accept them. Properly paired surrogates are tested
+ * in the non-BMP test.
+ *
* Note that this does not test all possible combinations, which might be an
* issue, particularly with combining marks, though they should be logically
* equivalent in that case.
@@ -121,9 +147,19 @@
*/
public void testClientToServerBMP() throws InvalidCharacterException {
delayTestFinish(TEST_FINISH_DELAY_MS);
- clientToServerVerifyRange(Character.MIN_CODE_POINT,
- Character.MIN_SUPPLEMENTARY_CODE_POINT, CHARACTER_BLOCK_SIZE,
- CHARACTER_BLOCK_SIZE);
+ if (isSafari2()) {
+ // Safari2 can't be fixed for many characters, including null
+ // We only guarantee that basic ISO-Latin characters are unmolested.
+ clientToServerVerifyRange(0x0001, 0x0300, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ } else {
+ clientToServerVerifyRange(Character.MIN_CODE_POINT,
+ Character.MIN_SURROGATE, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ clientToServerVerifyRange(Character.MAX_SURROGATE + 1,
+ Character.MIN_SUPPLEMENTARY_CODE_POINT, CHARACTER_BLOCK_SIZE,
+ CHARACTER_BLOCK_SIZE);
+ }
}
/**