Merge from AOSP
Change-Id: I83f2ba38dca0fa86e9ff802e5df02311f6bc6e99
diff --git a/Android.mk b/Android.mk
index b969317..0532402 100644
--- a/Android.mk
+++ b/Android.mk
@@ -58,6 +58,7 @@
dalvik \
$(HOST_OUT)/bin/dalvikvm \
$(HOST_OUT)/bin/dexopt \
+ $(HOST_OUT)/lib/libjavacore.so \
cacerts-host \
$(HOST_OUT)/usr/share/zoneinfo/zoneinfo.dat \
$(HOST_OUT)/usr/share/zoneinfo/zoneinfo.idx \
diff --git a/Docs.mk b/Docs.mk
index 8b5e469..875a008 100644
--- a/Docs.mk
+++ b/Docs.mk
@@ -21,7 +21,6 @@
dalvik/src/main/java/dalvik/annotation \
dalvik/src/main/java/dalvik/bytecode \
json/src/main/java \
- junit/src/main/java \
luni/src/main/java/java \
luni/src/main/java/javax \
luni/src/main/java/org/xml/sax \
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 7179fda..18fa870 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -88,16 +88,6 @@
core-intermediates := ${intermediates}
-# Make core-junit
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-main-java-files-under,junit)
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core
-LOCAL_JAVACFLAGS := $(local_javac_flags)
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := core-junit
-include $(BUILD_JAVA_LIBRARY)
-
# Make the core-tests library.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,dalvik dom json luni support xml)
@@ -153,17 +143,6 @@
include $(BUILD_HOST_JAVA_LIBRARY)
- # Make core-junit
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES := $(call all-main-java-files-under,junit)
- LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-hostdex
- LOCAL_JAVACFLAGS := $(local_javac_flags)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := core-junit-hostdex
- LOCAL_BUILD_HOST_DEX := true
- include $(BUILD_HOST_JAVA_LIBRARY)
-
# Make the core-tests library.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-test-java-files-under,dalvik dom json luni support xml)
diff --git a/NativeCode.mk b/NativeCode.mk
index 85b38e1..2a222b1 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -65,8 +65,9 @@
core_c_includes := $(sort libcore/include $(LOCAL_C_INCLUDES) $(JNI_H_INCLUDE))
core_shared_libraries := $(sort $(LOCAL_SHARED_LIBRARIES))
core_static_libraries := $(sort $(LOCAL_STATIC_LIBRARIES))
-core_cflags := -fvisibility=hidden -fvisibility-inlines-hidden
+core_cflags := -fvisibility=hidden
core_cflags += '-DGCC_HIDDEN=__attribute__((visibility("hidden")))'
+core_cppflags := -fvisibility-inlines-hidden
#
@@ -75,8 +76,9 @@
include $(CLEAR_VARS)
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-but-set-variable
+LOCAL_CFLAGS += -Wall -Wextra -Werror
LOCAL_CFLAGS += $(core_cflags)
+LOCAL_CPPFLAGS += $(core_cppflags)
ifeq ($(TARGET_ARCH),arm)
# Ignore "note: the mangling of 'va_list' has changed in GCC 4.4"
LOCAL_CFLAGS += -Wno-psabi
@@ -85,7 +87,7 @@
# Define the rules.
LOCAL_SRC_FILES := $(core_src_files)
LOCAL_C_INCLUDES := $(core_c_includes)
-LOCAL_SHARED_LIBRARIES := $(core_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libexpat libicuuc libicui18n libssl libcrypto libz libnativehelper
LOCAL_STATIC_LIBRARIES := $(core_static_libraries)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacore
@@ -93,7 +95,7 @@
LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
LOCAL_SHARED_LIBRARIES += libstlport
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
#
# Build for the host.
@@ -105,9 +107,11 @@
LOCAL_SRC_FILES := $(core_src_files)
LOCAL_CFLAGS += $(core_cflags)
LOCAL_C_INCLUDES := $(core_c_includes)
- LOCAL_SHARED_LIBRARIES := $(core_shared_libraries)
- LOCAL_STATIC_LIBRARIES := $(core_static_libraries)
+ LOCAL_CPPFLAGS += $(core_cppflags)
+ LOCAL_LDLIBS += -ldl -lpthread
LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := libjavacore-host
- include $(BUILD_HOST_STATIC_LIBRARY)
+ LOCAL_MODULE := libjavacore
+ LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libexpat libicuuc libicui18n libssl libcrypto libz-host
+ LOCAL_STATIC_LIBRARIES := $(core_static_libraries)
+ include $(BUILD_HOST_SHARED_LIBRARY)
endif
diff --git a/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java b/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
index f253ee7..1209b2e 100644
--- a/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
+++ b/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
@@ -55,7 +55,7 @@
*/
// BEGIN(libcore-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
MAXIMUM_VALUE = 65535;
- MAXIMUM_PACKED_VALUE = 511;
+ MAXIMUM_PACKED_VALUE = 255;
// END(libcore-maximum-values)
}
diff --git a/dalvik/src/main/java/dalvik/bytecode/Opcodes.java b/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
index 58f0f7d7..f758d65 100644
--- a/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
+++ b/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
@@ -245,47 +245,87 @@
int OP_SHL_INT_LIT8 = 0x00e0;
int OP_SHR_INT_LIT8 = 0x00e1;
int OP_USHR_INT_LIT8 = 0x00e2;
- int OP_CONST_CLASS_JUMBO = 0x00ff;
- int OP_CHECK_CAST_JUMBO = 0x01ff;
- int OP_INSTANCE_OF_JUMBO = 0x02ff;
- int OP_NEW_INSTANCE_JUMBO = 0x03ff;
- int OP_NEW_ARRAY_JUMBO = 0x04ff;
- int OP_FILLED_NEW_ARRAY_JUMBO = 0x05ff;
- int OP_IGET_JUMBO = 0x06ff;
- int OP_IGET_WIDE_JUMBO = 0x07ff;
- int OP_IGET_OBJECT_JUMBO = 0x08ff;
- int OP_IGET_BOOLEAN_JUMBO = 0x09ff;
- int OP_IGET_BYTE_JUMBO = 0x0aff;
- int OP_IGET_CHAR_JUMBO = 0x0bff;
- int OP_IGET_SHORT_JUMBO = 0x0cff;
- int OP_IPUT_JUMBO = 0x0dff;
- int OP_IPUT_WIDE_JUMBO = 0x0eff;
- int OP_IPUT_OBJECT_JUMBO = 0x0fff;
- int OP_IPUT_BOOLEAN_JUMBO = 0x10ff;
- int OP_IPUT_BYTE_JUMBO = 0x11ff;
- int OP_IPUT_CHAR_JUMBO = 0x12ff;
- int OP_IPUT_SHORT_JUMBO = 0x13ff;
- int OP_SGET_JUMBO = 0x14ff;
- int OP_SGET_WIDE_JUMBO = 0x15ff;
- int OP_SGET_OBJECT_JUMBO = 0x16ff;
- int OP_SGET_BOOLEAN_JUMBO = 0x17ff;
- int OP_SGET_BYTE_JUMBO = 0x18ff;
- int OP_SGET_CHAR_JUMBO = 0x19ff;
- int OP_SGET_SHORT_JUMBO = 0x1aff;
- int OP_SPUT_JUMBO = 0x1bff;
- int OP_SPUT_WIDE_JUMBO = 0x1cff;
- int OP_SPUT_OBJECT_JUMBO = 0x1dff;
- int OP_SPUT_BOOLEAN_JUMBO = 0x1eff;
- int OP_SPUT_BYTE_JUMBO = 0x1fff;
- int OP_SPUT_CHAR_JUMBO = 0x20ff;
- int OP_SPUT_SHORT_JUMBO = 0x21ff;
- int OP_INVOKE_VIRTUAL_JUMBO = 0x22ff;
- int OP_INVOKE_SUPER_JUMBO = 0x23ff;
- int OP_INVOKE_DIRECT_JUMBO = 0x24ff;
- int OP_INVOKE_STATIC_JUMBO = 0x25ff;
- int OP_INVOKE_INTERFACE_JUMBO = 0x26ff;
// END(libcore-opcodes)
+ /** Never implemented; do not use. */
+ int OP_CONST_CLASS_JUMBO = 0x00ff;
+ /** Never implemented; do not use. */
+ int OP_CHECK_CAST_JUMBO = 0x01ff;
+ /** Never implemented; do not use. */
+ int OP_INSTANCE_OF_JUMBO = 0x02ff;
+ /** Never implemented; do not use. */
+ int OP_NEW_INSTANCE_JUMBO = 0x03ff;
+ /** Never implemented; do not use. */
+ int OP_NEW_ARRAY_JUMBO = 0x04ff;
+ /** Never implemented; do not use. */
+ int OP_FILLED_NEW_ARRAY_JUMBO = 0x05ff;
+ /** Never implemented; do not use. */
+ int OP_IGET_JUMBO = 0x06ff;
+ /** Never implemented; do not use. */
+ int OP_IGET_WIDE_JUMBO = 0x07ff;
+ /** Never implemented; do not use. */
+ int OP_IGET_OBJECT_JUMBO = 0x08ff;
+ /** Never implemented; do not use. */
+ int OP_IGET_BOOLEAN_JUMBO = 0x09ff;
+ /** Never implemented; do not use. */
+ int OP_IGET_BYTE_JUMBO = 0x0aff;
+ /** Never implemented; do not use. */
+ int OP_IGET_CHAR_JUMBO = 0x0bff;
+ /** Never implemented; do not use. */
+ int OP_IGET_SHORT_JUMBO = 0x0cff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_JUMBO = 0x0dff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_WIDE_JUMBO = 0x0eff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_OBJECT_JUMBO = 0x0fff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_BOOLEAN_JUMBO = 0x10ff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_BYTE_JUMBO = 0x11ff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_CHAR_JUMBO = 0x12ff;
+ /** Never implemented; do not use. */
+ int OP_IPUT_SHORT_JUMBO = 0x13ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_JUMBO = 0x14ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_WIDE_JUMBO = 0x15ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_OBJECT_JUMBO = 0x16ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_BOOLEAN_JUMBO = 0x17ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_BYTE_JUMBO = 0x18ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_CHAR_JUMBO = 0x19ff;
+ /** Never implemented; do not use. */
+ int OP_SGET_SHORT_JUMBO = 0x1aff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_JUMBO = 0x1bff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_WIDE_JUMBO = 0x1cff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_OBJECT_JUMBO = 0x1dff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_BOOLEAN_JUMBO = 0x1eff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_BYTE_JUMBO = 0x1fff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_CHAR_JUMBO = 0x20ff;
+ /** Never implemented; do not use. */
+ int OP_SPUT_SHORT_JUMBO = 0x21ff;
+ /** Never implemented; do not use. */
+ int OP_INVOKE_VIRTUAL_JUMBO = 0x22ff;
+ /** Never implemented; do not use. */
+ int OP_INVOKE_SUPER_JUMBO = 0x23ff;
+ /** Never implemented; do not use. */
+ int OP_INVOKE_DIRECT_JUMBO = 0x24ff;
+ /** Never implemented; do not use. */
+ int OP_INVOKE_STATIC_JUMBO = 0x25ff;
+ /** Never implemented; do not use. */
+ int OP_INVOKE_INTERFACE_JUMBO = 0x26ff;
+
/*
* The rest of these are either generated by dexopt for optimized
* code, or inserted by the VM at runtime. They are never generated
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index dc3e063..8db3985 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -20,6 +20,9 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
/**
* Manipulates DEX files. The class is similar in principle to
@@ -90,6 +93,19 @@
* Enable optional features.
*/
private DexFile(String sourceName, String outputName, int flags) throws IOException {
+ if (outputName != null) {
+ try {
+ String parent = new File(outputName).getParent();
+ if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
+ throw new IllegalArgumentException("Optimized data directory " + parent
+ + " is not owned by the current user. Shared storage cannot protect"
+ + " your application from code injection attacks.");
+ }
+ } catch (ErrnoException ignored) {
+ // assume we'll fail with a more contextual error later
+ }
+ }
+
mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
diff --git a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
index 46e18ae..50e2fc2 100644
--- a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
+++ b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
@@ -61,7 +61,7 @@
gMethods, NELEM(gMethods));
if (result != 0) {
/* print warning, but allow to continue */
- LOGW("WARNING: NativeTestTarget not registered\n");
+ ALOGW("WARNING: NativeTestTarget not registered\n");
env->ExceptionClear();
}
return 0;
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 8a9952c..6fc48cd 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -3,6 +3,26 @@
*/
[
{
+ description: "libcore.java.io.OldFileTest#test_deleteOnExit fails on IRM05 mysid-user",
+ name: "libcore.java.io.OldFileTest#test_deleteOnExit",
+ bug: 5834665
+},
+{
+ description: "libcore.java.net.URLConnectionTest#testServerShutdownInput fails on ICL27 mysid-userdebug",
+ name: "libcore.java.net.URLConnectionTest#testServerShutdownInput",
+ bug: 5534202
+},
+{
+ description: "libcore.java.security.KeyPairGeneratorTest long test is too long",
+ name: "libcore.java.security.KeyPairGeneratorTest#test_getInstance",
+ bug: 5513723
+},
+{
+ description: "Support digest authentication in HttpURLConnection",
+ name: "libcore.net.http.ParsedHeadersTest#testParseChallengesWithManyParameters",
+ bug: 6156454
+},
+{
description: "Without no security manager, we don't care if checkPermission's argument is null",
name: "org.apache.harmony.security.tests.java.security.AccessController2Test#test_checkPermission_NullParameter",
result: EXEC_FAILED
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 7915a10..ae650ea 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -200,11 +200,6 @@
bug: 3057090
},
{
- description: "finalize() called on objects whose constructor didn't complete normally",
- name: "libcore.java.lang.SystemTest#testBackFromTheDead",
- bug: 3342343
-},
-{
description: "DecimalFormat is limited to 127 digits",
name: "libcore.java.text.DecimalFormatTest#test_setMaximumIntegerDigits",
bug: 2400429
@@ -312,16 +307,6 @@
modes: [ "host" ]
},
{
- description: "Fails in CTS but passes under run-core-tests",
- result: EXEC_FAILED,
- name: "libcore.java.io.OldFileTest#test_deleteOnExit"
-},
-{
- description: "Fails in CTS but passes under run-core-tests",
- result: EXEC_FAILED,
- name: "tests.api.java.io.SerializationStressTest4#test_writeObject_Proxy"
-},
-{
description: "Defining classes from byte[] not supported in Android",
result: EXEC_FAILED,
name: "libcore.java.lang.OldClassTest#test_getClasses_subtest0"
@@ -332,14 +317,6 @@
name: "libcore.java.lang.OldClassTest#test_getProtectionDomain"
},
{
- description: "Fails in CTS but passes under run-core-tests",
- result: EXEC_FAILED,
- names: [
- "tests.api.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface",
- "tests.api.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_DateTimeConversion"
- ]
-},
-{
description: "Runtime.getRuntime().traceMethodCalls(true) doesn't return on the host, fails in CTS",
bug: 3447964,
name: "libcore.java.lang.OldRuntimeTest#test_traceMethodCalls"
@@ -351,14 +328,6 @@
name: "tests.api.java.util.ResourceBundleTest#test_getBundleLjava_lang_StringLjava_util_LocaleLjava_lang_ClassLoader"
},
{
- description: "Fails in CTS but passes under run-core-tests",
- result: EXEC_FAILED,
- names: [
- "tests.api.java.nio.charset.CharsetProviderTest#testForName_InsufficientPrivilege",
- "tests.api.java.nio.charset.CharsetProviderTest#testIsSupported_And_ForName_NormalProvider"
- ]
-},
-{
description: "Fails (probably) because no protection domain is set.",
result: EXEC_FAILED,
names: [
diff --git a/junit/MODULE_LICENSE_CPL b/junit/MODULE_LICENSE_CPL
deleted file mode 100644
index 541dbb5..0000000
--- a/junit/MODULE_LICENSE_CPL
+++ /dev/null
@@ -1 +0,0 @@
-http://www.opensource.org/licenses/cpl1.0.php
diff --git a/junit/src/main/java/junit/extensions/ActiveTestSuite.java b/junit/src/main/java/junit/extensions/ActiveTestSuite.java
deleted file mode 100644
index 8b62853..0000000
--- a/junit/src/main/java/junit/extensions/ActiveTestSuite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package junit.extensions;
-
-import junit.framework.*;
-
-/**
- * A TestSuite for active Tests. It runs each
- * test in a separate thread and waits until all
- * threads have terminated.
- * -- Aarhus Radisson Scandinavian Center 11th floor
- */
-public class ActiveTestSuite extends TestSuite {
- private volatile int fActiveTestDeathCount;
-
- public ActiveTestSuite() {
- }
-
- public ActiveTestSuite(Class theClass) {
- super(theClass);
- }
-
- public ActiveTestSuite(String name) {
- super (name);
- }
-
- public ActiveTestSuite(Class theClass, String name) {
- super(theClass, name);
- }
-
- public void run(TestResult result) {
- fActiveTestDeathCount= 0;
- super.run(result);
- waitUntilFinished();
- }
-
- public void runTest(final Test test, final TestResult result) {
- Thread t= new Thread() {
- public void run() {
- try {
- // inlined due to limitation in VA/Java
- //ActiveTestSuite.super.runTest(test, result);
- test.run(result);
- } finally {
- ActiveTestSuite.this.runFinished(test);
- }
- }
- };
- t.start();
- }
-
- synchronized void waitUntilFinished() {
- while (fActiveTestDeathCount < testCount()) {
- try {
- wait();
- } catch (InterruptedException e) {
- return; // ignore
- }
- }
- }
-
- synchronized public void runFinished(Test test) {
- fActiveTestDeathCount++;
- notifyAll();
- }
-}
diff --git a/junit/src/main/java/junit/extensions/ExceptionTestCase.java b/junit/src/main/java/junit/extensions/ExceptionTestCase.java
deleted file mode 100644
index de64b5b..0000000
--- a/junit/src/main/java/junit/extensions/ExceptionTestCase.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package junit.extensions;
-
-import junit.framework.*;
-
-/**
- * A TestCase that expects an Exception of class fExpected to be thrown.
- * The other way to check that an expected exception is thrown is:
- * <pre>
- * try {
- * shouldThrow();
- * }
- * catch (SpecialException e) {
- * return;
- * }
- * fail("Expected SpecialException");
- * </pre>
- *
- * To use ExceptionTestCase, create a TestCase like:
- * <pre>
- * new ExceptionTestCase("testShouldThrow", SpecialException.class);
- * </pre>
- */
-public class ExceptionTestCase extends TestCase {
- Class fExpected;
-
- public ExceptionTestCase(String name, Class exception) {
- super(name);
- fExpected= exception;
- }
- /**
- * Execute the test method expecting that an Exception of
- * class fExpected or one of its subclasses will be thrown
- */
- protected void runTest() throws Throwable {
- try {
- super.runTest();
- }
- catch (Exception e) {
- if (fExpected.isAssignableFrom(e.getClass()))
- return;
- else
- throw e;
- }
- fail("Expected exception " + fExpected);
- }
-}
diff --git a/junit/src/main/java/junit/extensions/RepeatedTest.java b/junit/src/main/java/junit/extensions/RepeatedTest.java
deleted file mode 100644
index 34f2541..0000000
--- a/junit/src/main/java/junit/extensions/RepeatedTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package junit.extensions;
-
-import junit.framework.*;
-
-/**
- * A Decorator that runs a test repeatedly.
- *
- */
-public class RepeatedTest extends TestDecorator {
- private int fTimesRepeat;
-
- public RepeatedTest(Test test, int repeat) {
- super(test);
- if (repeat < 0)
- throw new IllegalArgumentException("Repetition count must be > 0");
- fTimesRepeat= repeat;
- }
- public int countTestCases() {
- return super.countTestCases()*fTimesRepeat;
- }
- public void run(TestResult result) {
- for (int i= 0; i < fTimesRepeat; i++) {
- if (result.shouldStop())
- break;
- super.run(result);
- }
- }
- public String toString() {
- return super.toString()+"(repeated)";
- }
-}
diff --git a/junit/src/main/java/junit/extensions/TestDecorator.java b/junit/src/main/java/junit/extensions/TestDecorator.java
deleted file mode 100644
index cfbd021..0000000
--- a/junit/src/main/java/junit/extensions/TestDecorator.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package junit.extensions;
-
-import junit.framework.*;
-
-/**
- * A Decorator for Tests. Use TestDecorator as the base class
- * for defining new test decorators. Test decorator subclasses
- * can be introduced to add behavior before or after a test
- * is run.
- *
- */
-public class TestDecorator extends Assert implements Test {
- protected Test fTest;
-
- public TestDecorator(Test test) {
- fTest= test;
- }
- /**
- * The basic run behavior.
- */
- public void basicRun(TestResult result) {
- fTest.run(result);
- }
- public int countTestCases() {
- return fTest.countTestCases();
- }
- public void run(TestResult result) {
- basicRun(result);
- }
-
- public String toString() {
- return fTest.toString();
- }
-
- public Test getTest() {
- return fTest;
- }
-}
diff --git a/junit/src/main/java/junit/extensions/TestSetup.java b/junit/src/main/java/junit/extensions/TestSetup.java
deleted file mode 100644
index 3651501..0000000
--- a/junit/src/main/java/junit/extensions/TestSetup.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package junit.extensions;
-
-import junit.framework.*;
-
-/**
- * A Decorator to set up and tear down additional fixture state.
- * Subclass TestSetup and insert it into your tests when you want
- * to set up additional state once before the tests are run.
- */
-public class TestSetup extends TestDecorator {
-
- public TestSetup(Test test) {
- super(test);
- }
- public void run(final TestResult result) {
- Protectable p= new Protectable() {
- public void protect() throws Exception {
- setUp();
- basicRun(result);
- tearDown();
- }
- };
- result.runProtected(this, p);
- }
- /**
- * Sets up the fixture. Override to set up additional fixture
- * state.
- */
- protected void setUp() throws Exception {
- }
- /**
- * Tears down the fixture. Override to tear down the additional
- * fixture state.
- */
- protected void tearDown() throws Exception {
- }
-}
diff --git a/junit/src/main/java/junit/extensions/package.html b/junit/src/main/java/junit/extensions/package.html
deleted file mode 100644
index 6b4be72..0000000
--- a/junit/src/main/java/junit/extensions/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-{@hide} - Not needed for 1.0 SDK
-</BODY>
-</HTML>
diff --git a/junit/src/main/java/junit/framework/Assert.java b/junit/src/main/java/junit/framework/Assert.java
deleted file mode 100644
index 289449a..0000000
--- a/junit/src/main/java/junit/framework/Assert.java
+++ /dev/null
@@ -1,291 +0,0 @@
-package junit.framework;
-
-/**
- * A set of assert methods. Messages are only displayed when an assert fails.
- */
-
-public class Assert {
- /**
- * Protect constructor since it is a static only class
- */
- protected Assert() {
- }
-
- /**
- * Asserts that a condition is true. If it isn't it throws
- * an AssertionFailedError with the given message.
- */
- static public void assertTrue(String message, boolean condition) {
- if (!condition)
- fail(message);
- }
- /**
- * Asserts that a condition is true. If it isn't it throws
- * an AssertionFailedError.
- */
- static public void assertTrue(boolean condition) {
- assertTrue(null, condition);
- }
- /**
- * Asserts that a condition is false. If it isn't it throws
- * an AssertionFailedError with the given message.
- */
- static public void assertFalse(String message, boolean condition) {
- assertTrue(message, !condition);
- }
- /**
- * Asserts that a condition is false. If it isn't it throws
- * an AssertionFailedError.
- */
- static public void assertFalse(boolean condition) {
- assertFalse(null, condition);
- }
- /**
- * Fails a test with the given message.
- */
- static public void fail(String message) {
- throw new AssertionFailedError(message);
- }
- /**
- * Fails a test with no message.
- */
- static public void fail() {
- fail(null);
- }
- /**
- * Asserts that two objects are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, Object expected, Object actual) {
- if (expected == null && actual == null)
- return;
- if (expected != null && expected.equals(actual))
- return;
- failNotEquals(message, expected, actual);
- }
- /**
- * Asserts that two objects are equal. If they are not
- * an AssertionFailedError is thrown.
- */
- static public void assertEquals(Object expected, Object actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two Strings are equal.
- */
- static public void assertEquals(String message, String expected, String actual) {
- if (expected == null && actual == null)
- return;
- if (expected != null && expected.equals(actual))
- return;
- throw new ComparisonFailure(message, expected, actual);
- }
- /**
- * Asserts that two Strings are equal.
- */
- static public void assertEquals(String expected, String actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two doubles are equal concerning a delta. If they are not
- * an AssertionFailedError is thrown with the given message. If the expected
- * value is infinity then the delta value is ignored.
- */
- static public void assertEquals(String message, double expected, double actual, double delta) {
- // handle infinity specially since subtracting to infinite values gives NaN and the
- // the following test fails
- if (Double.isInfinite(expected)) {
- if (!(expected == actual))
- failNotEquals(message, new Double(expected), new Double(actual));
- } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
- failNotEquals(message, new Double(expected), new Double(actual));
- }
- /**
- * Asserts that two doubles are equal concerning a delta. If the expected
- * value is infinity then the delta value is ignored.
- */
- static public void assertEquals(double expected, double actual, double delta) {
- assertEquals(null, expected, actual, delta);
- }
- /**
- * Asserts that two floats are equal concerning a delta. If they are not
- * an AssertionFailedError is thrown with the given message. If the expected
- * value is infinity then the delta value is ignored.
- */
- static public void assertEquals(String message, float expected, float actual, float delta) {
- // handle infinity specially since subtracting to infinite values gives NaN and the
- // the following test fails
- if (Float.isInfinite(expected)) {
- if (!(expected == actual))
- failNotEquals(message, new Float(expected), new Float(actual));
- } else if (!(Math.abs(expected-actual) <= delta))
- failNotEquals(message, new Float(expected), new Float(actual));
- }
- /**
- * Asserts that two floats are equal concerning a delta. If the expected
- * value is infinity then the delta value is ignored.
- */
- static public void assertEquals(float expected, float actual, float delta) {
- assertEquals(null, expected, actual, delta);
- }
- /**
- * Asserts that two longs are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, long expected, long actual) {
- assertEquals(message, new Long(expected), new Long(actual));
- }
- /**
- * Asserts that two longs are equal.
- */
- static public void assertEquals(long expected, long actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two booleans are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, boolean expected, boolean actual) {
- assertEquals(message, new Boolean(expected), new Boolean(actual));
- }
- /**
- * Asserts that two booleans are equal.
- */
- static public void assertEquals(boolean expected, boolean actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two bytes are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, byte expected, byte actual) {
- assertEquals(message, new Byte(expected), new Byte(actual));
- }
- /**
- * Asserts that two bytes are equal.
- */
- static public void assertEquals(byte expected, byte actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two chars are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, char expected, char actual) {
- assertEquals(message, new Character(expected), new Character(actual));
- }
- /**
- * Asserts that two chars are equal.
- */
- static public void assertEquals(char expected, char actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two shorts are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, short expected, short actual) {
- assertEquals(message, new Short(expected), new Short(actual));
- }
- /**
- * Asserts that two shorts are equal.
- */
- static public void assertEquals(short expected, short actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that two ints are equal. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertEquals(String message, int expected, int actual) {
- assertEquals(message, new Integer(expected), new Integer(actual));
- }
- /**
- * Asserts that two ints are equal.
- */
- static public void assertEquals(int expected, int actual) {
- assertEquals(null, expected, actual);
- }
- /**
- * Asserts that an object isn't null.
- */
- static public void assertNotNull(Object object) {
- assertNotNull(null, object);
- }
- /**
- * Asserts that an object isn't null. If it is
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertNotNull(String message, Object object) {
- assertTrue(message, object != null);
- }
- /**
- * Asserts that an object is null.
- */
- static public void assertNull(Object object) {
- assertNull(null, object);
- }
- /**
- * Asserts that an object is null. If it is not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertNull(String message, Object object) {
- assertTrue(message, object == null);
- }
- /**
- * Asserts that two objects refer to the same object. If they are not
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertSame(String message, Object expected, Object actual) {
- if (expected == actual)
- return;
- failNotSame(message, expected, actual);
- }
- /**
- * Asserts that two objects refer to the same object. If they are not
- * the same an AssertionFailedError is thrown.
- */
- static public void assertSame(Object expected, Object actual) {
- assertSame(null, expected, actual);
- }
- /**
- * Asserts that two objects do not refer to the same object. If they are
- * an AssertionFailedError is thrown with the given message.
- */
- static public void assertNotSame(String message, Object expected, Object actual) {
- if (expected == actual)
- failSame(message);
- }
- /**
- * Asserts that two objects do not refer to the same object. If they are
- * the same an AssertionFailedError is thrown.
- */
- static public void assertNotSame(Object expected, Object actual) {
- assertNotSame(null, expected, actual);
- }
-
- static private void failSame(String message) {
- String formatted= "";
- if (message != null)
- formatted= message+" ";
- fail(formatted+"expected not same");
- }
-
- static private void failNotSame(String message, Object expected, Object actual) {
- String formatted= "";
- if (message != null)
- formatted= message+" ";
- fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
- }
-
- static private void failNotEquals(String message, Object expected, Object actual) {
- fail(format(message, expected, actual));
- }
-
- static String format(String message, Object expected, Object actual) {
- String formatted= "";
- if (message != null)
- formatted= message+" ";
- return formatted+"expected:<"+expected+"> but was:<"+actual+">";
- }
-}
diff --git a/junit/src/main/java/junit/framework/AssertionFailedError.java b/junit/src/main/java/junit/framework/AssertionFailedError.java
deleted file mode 100644
index e9cb3a3..0000000
--- a/junit/src/main/java/junit/framework/AssertionFailedError.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package junit.framework;
-
-/**
- * Thrown when an assertion failed.
- */
-public class AssertionFailedError extends Error {
-
- public AssertionFailedError () {
- }
- public AssertionFailedError (String message) {
- super (message);
- }
-}
diff --git a/junit/src/main/java/junit/framework/ComparisonFailure.java b/junit/src/main/java/junit/framework/ComparisonFailure.java
deleted file mode 100644
index ccd476b..0000000
--- a/junit/src/main/java/junit/framework/ComparisonFailure.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package junit.framework;
-
-/**
- * Thrown when an assert equals for Strings failed.
- *
- * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com
- */
-public class ComparisonFailure extends AssertionFailedError {
- private String fExpected;
- private String fActual;
-
- /**
- * Constructs a comparison failure.
- * @param message the identifying message or null
- * @param expected the expected string value
- * @param actual the actual string value
- */
- public ComparisonFailure (String message, String expected, String actual) {
- super (message);
- fExpected= expected;
- fActual= actual;
- }
-
- /**
- * Returns "..." in place of common prefix and "..." in
- * place of common suffix between expected and actual.
- *
- * @see java.lang.Throwable#getMessage()
- */
- public String getMessage() {
- if (fExpected == null || fActual == null)
- return Assert.format(super.getMessage(), fExpected, fActual);
-
- int end= Math.min(fExpected.length(), fActual.length());
-
- int i= 0;
- for (; i < end; i++) {
- if (fExpected.charAt(i) != fActual.charAt(i))
- break;
- }
- int j= fExpected.length()-1;
- int k= fActual.length()-1;
- for (; k >= i && j >= i; k--,j--) {
- if (fExpected.charAt(j) != fActual.charAt(k))
- break;
- }
- String actual, expected;
-
- // equal strings
- if (j < i && k < i) {
- expected= fExpected;
- actual= fActual;
- } else {
- expected= fExpected.substring(i, j+1);
- actual= fActual.substring(i, k+1);
- if (i <= end && i > 0) {
- expected= "..."+expected;
- actual= "..."+actual;
- }
-
- if (j < fExpected.length()-1)
- expected= expected+"...";
- if (k < fActual.length()-1)
- actual= actual+"...";
- }
- return Assert.format(super.getMessage(), expected, actual);
- }
-}
diff --git a/junit/src/main/java/junit/framework/Protectable.java b/junit/src/main/java/junit/framework/Protectable.java
deleted file mode 100644
index 9a63c96..0000000
--- a/junit/src/main/java/junit/framework/Protectable.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package junit.framework;
-
-/**
- * A <em>Protectable</em> can be run and can throw a Throwable.
- *
- * @see TestResult
- */
-public interface Protectable {
-
- /**
- * Run the the following method protected.
- */
- public abstract void protect() throws Throwable;
-}
diff --git a/junit/src/main/java/junit/framework/Test.java b/junit/src/main/java/junit/framework/Test.java
deleted file mode 100644
index 94f25cf..0000000
--- a/junit/src/main/java/junit/framework/Test.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package junit.framework;
-
-/**
- * A <em>Test</em> can be run and collect its results.
- *
- * @see TestResult
- */
-public interface Test {
- /**
- * Counts the number of test cases that will be run by this test.
- */
- public abstract int countTestCases();
- /**
- * Runs a test and collects its result in a TestResult instance.
- */
- public abstract void run(TestResult result);
-}
diff --git a/junit/src/main/java/junit/framework/TestCase.java b/junit/src/main/java/junit/framework/TestCase.java
deleted file mode 100644
index f29e8d2..0000000
--- a/junit/src/main/java/junit/framework/TestCase.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package junit.framework;
-
-import java.lang.reflect.*;
-
-/**
- * A test case defines the fixture to run multiple tests. To define a test case<br>
- * 1) implement a subclass of TestCase<br>
- * 2) define instance variables that store the state of the fixture<br>
- * 3) initialize the fixture state by overriding <code>setUp</code><br>
- * 4) clean-up after a test by overriding <code>tearDown</code>.<br>
- * Each test runs in its own fixture so there
- * can be no side effects among test runs.
- * Here is an example:
- * <pre>
- * public class MathTest extends TestCase {
- * protected double fValue1;
- * protected double fValue2;
- *
- * protected void setUp() {
- * fValue1= 2.0;
- * fValue2= 3.0;
- * }
- * }
- * </pre>
- *
- * For each test implement a method which interacts
- * with the fixture. Verify the expected results with assertions specified
- * by calling <code>assertTrue</code> with a boolean.
- * <pre>
- * public void testAdd() {
- * double result= fValue1 + fValue2;
- * assertTrue(result == 5.0);
- * }
- * </pre>
- * Once the methods are defined you can run them. The framework supports
- * both a static type safe and more dynamic way to run a test.
- * In the static way you override the runTest method and define the method to
- * be invoked. A convenient way to do so is with an anonymous inner class.
- * <pre>
- * TestCase test= new MathTest("add") {
- * public void runTest() {
- * testAdd();
- * }
- * };
- * test.run();
- * </pre>
- * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds
- * and invokes a method.
- * In this case the name of the test case has to correspond to the test method
- * to be run.
- * <pre>
- * TestCase= new MathTest("testAdd");
- * test.run();
- * </pre>
- * The tests to be run can be collected into a TestSuite. JUnit provides
- * different <i>test runners</i> which can run a test suite and collect the results.
- * A test runner either expects a static method <code>suite</code> as the entry
- * point to get a test to run or it will extract the suite automatically.
- * <pre>
- * public static Test suite() {
- * suite.addTest(new MathTest("testAdd"));
- * suite.addTest(new MathTest("testDivideByZero"));
- * return suite;
- * }
- * </pre>
- * @see TestResult
- * @see TestSuite
- */
-
-public abstract class TestCase extends Assert implements Test {
- /**
- * the name of the test case
- */
- private String fName;
-
- /**
- * No-arg constructor to enable serialization. This method
- * is not intended to be used by mere mortals without calling setName().
- */
- public TestCase() {
- fName= null;
- }
- /**
- * Constructs a test case with the given name.
- */
- public TestCase(String name) {
- fName= name;
- }
- /**
- * Counts the number of test cases executed by run(TestResult result).
- */
- public int countTestCases() {
- return 1;
- }
- /**
- * Creates a default TestResult object
- *
- * @see TestResult
- */
- protected TestResult createResult() {
- return new TestResult();
- }
- /**
- * A convenience method to run this test, collecting the results with a
- * default TestResult object.
- *
- * @see TestResult
- */
- public TestResult run() {
- TestResult result= createResult();
- run(result);
- return result;
- }
- /**
- * Runs the test case and collects the results in TestResult.
- */
- public void run(TestResult result) {
- result.run(this);
- }
- /**
- * Runs the bare test sequence.
- * @exception Throwable if any exception is thrown
- */
- public void runBare() throws Throwable {
- setUp();
- try {
- runTest();
- }
- finally {
- tearDown();
- }
- }
- /**
- * Override to run the test and assert its state.
- * @exception Throwable if any exception is thrown
- */
- protected void runTest() throws Throwable {
- assertNotNull(fName);
- Method runMethod= null;
- try {
- // use getMethod to get all public inherited
- // methods. getDeclaredMethods returns all
- // methods of this class but excludes the
- // inherited ones.
- runMethod= getClass().getMethod(fName, (Class[]) null);
- } catch (NoSuchMethodException e) {
- fail("Method \""+fName+"\" not found");
- }
- if (!Modifier.isPublic(runMethod.getModifiers())) {
- fail("Method \""+fName+"\" should be public");
- }
-
- try {
- runMethod.invoke(this, (Object[]) null);
- }
- catch (InvocationTargetException e) {
- e.fillInStackTrace();
- throw e.getTargetException();
- }
- catch (IllegalAccessException e) {
- e.fillInStackTrace();
- throw e;
- }
- }
- /**
- * Sets up the fixture, for example, open a network connection.
- * This method is called before a test is executed.
- */
- protected void setUp() throws Exception {
- }
- /**
- * Tears down the fixture, for example, close a network connection.
- * This method is called after a test is executed.
- */
- protected void tearDown() throws Exception {
- }
- /**
- * Returns a string representation of the test case
- */
- public String toString() {
- return getName() + "(" + getClass().getName() + ")";
- }
- /**
- * Gets the name of a TestCase
- * @return returns a String
- */
- public String getName() {
- return fName;
- }
- /**
- * Sets the name of a TestCase
- * @param name The name to set
- */
- public void setName(String name) {
- fName= name;
- }
-}
diff --git a/junit/src/main/java/junit/framework/TestFailure.java b/junit/src/main/java/junit/framework/TestFailure.java
deleted file mode 100644
index 45614a3..0000000
--- a/junit/src/main/java/junit/framework/TestFailure.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package junit.framework;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-
-/**
- * A <code>TestFailure</code> collects a failed test together with
- * the caught exception.
- * @see TestResult
- */
-public class TestFailure extends Object {
- protected Test fFailedTest;
- protected Throwable fThrownException;
-
-
- /**
- * Constructs a TestFailure with the given test and exception.
- */
- public TestFailure(Test failedTest, Throwable thrownException) {
- fFailedTest= failedTest;
- fThrownException= thrownException;
- }
- /**
- * Gets the failed test.
- */
- public Test failedTest() {
- return fFailedTest;
- }
- /**
- * Gets the thrown exception.
- */
- public Throwable thrownException() {
- return fThrownException;
- }
- /**
- * Returns a short description of the failure.
- */
- public String toString() {
- StringBuffer buffer= new StringBuffer();
- buffer.append(fFailedTest+": "+fThrownException.getMessage());
- return buffer.toString();
- }
- public String trace() {
- StringWriter stringWriter= new StringWriter();
- PrintWriter writer= new PrintWriter(stringWriter);
- thrownException().printStackTrace(writer);
- StringBuffer buffer= stringWriter.getBuffer();
- return buffer.toString();
- }
- public String exceptionMessage() {
- return thrownException().getMessage();
- }
- public boolean isFailure() {
- return thrownException() instanceof AssertionFailedError;
- }
-}
diff --git a/junit/src/main/java/junit/framework/TestListener.java b/junit/src/main/java/junit/framework/TestListener.java
deleted file mode 100644
index 41c6ccf..0000000
--- a/junit/src/main/java/junit/framework/TestListener.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package junit.framework;
-
-/**
- * A Listener for test progress
- */
-public interface TestListener {
- /**
- * An error occurred.
- */
- public void addError(Test test, Throwable t);
- /**
- * A failure occurred.
- */
- public void addFailure(Test test, AssertionFailedError t);
- /**
- * A test ended.
- */
- public void endTest(Test test);
- /**
- * A test started.
- */
- public void startTest(Test test);
-}
diff --git a/junit/src/main/java/junit/framework/TestResult.java b/junit/src/main/java/junit/framework/TestResult.java
deleted file mode 100644
index bcca1de..0000000
--- a/junit/src/main/java/junit/framework/TestResult.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package junit.framework;
-
-import java.util.Vector;
-import java.util.Enumeration;
-
-/**
- * A <code>TestResult</code> collects the results of executing
- * a test case. It is an instance of the Collecting Parameter pattern.
- * The test framework distinguishes between <i>failures</i> and <i>errors</i>.
- * A failure is anticipated and checked for with assertions. Errors are
- * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>.
- *
- * @see Test
- */
-public class TestResult extends Object {
- protected Vector fFailures;
- protected Vector fErrors;
- protected Vector fListeners;
- protected int fRunTests;
- private boolean fStop;
-
- public TestResult() {
- fFailures= new Vector();
- fErrors= new Vector();
- fListeners= new Vector();
- fRunTests= 0;
- fStop= false;
- }
- /**
- * Adds an error to the list of errors. The passed in exception
- * caused the error.
- */
- public synchronized void addError(Test test, Throwable t) {
- fErrors.addElement(new TestFailure(test, t));
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).addError(test, t);
- }
- }
- /**
- * Adds a failure to the list of failures. The passed in exception
- * caused the failure.
- */
- public synchronized void addFailure(Test test, AssertionFailedError t) {
- fFailures.addElement(new TestFailure(test, t));
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).addFailure(test, t);
- }
- }
- /**
- * Registers a TestListener
- */
- public synchronized void addListener(TestListener listener) {
- fListeners.addElement(listener);
- }
- /**
- * Unregisters a TestListener
- */
- public synchronized void removeListener(TestListener listener) {
- fListeners.removeElement(listener);
- }
- /**
- * Returns a copy of the listeners.
- */
- private synchronized Vector cloneListeners() {
- return (Vector)fListeners.clone();
- }
- /**
- * Informs the result that a test was completed.
- */
- public void endTest(Test test) {
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).endTest(test);
- }
- }
- /**
- * Gets the number of detected errors.
- */
- public synchronized int errorCount() {
- return fErrors.size();
- }
- /**
- * Returns an Enumeration for the errors
- */
- public synchronized Enumeration errors() {
- return fErrors.elements();
- }
- /**
- * Gets the number of detected failures.
- */
- public synchronized int failureCount() {
- return fFailures.size();
- }
- /**
- * Returns an Enumeration for the failures
- */
- public synchronized Enumeration failures() {
- return fFailures.elements();
- }
- /**
- * Runs a TestCase.
- */
- protected void run(final TestCase test) {
- startTest(test);
- Protectable p= new Protectable() {
- public void protect() throws Throwable {
- test.runBare();
- }
- };
- runProtected(test, p);
-
- endTest(test);
- }
- /**
- * Gets the number of run tests.
- */
- public synchronized int runCount() {
- return fRunTests;
- }
- /**
- * Runs a TestCase.
- */
- public void runProtected(final Test test, Protectable p) {
- try {
- p.protect();
- }
- catch (AssertionFailedError e) {
- addFailure(test, e);
- }
- catch (ThreadDeath e) { // don't catch ThreadDeath by accident
- throw e;
- }
- catch (Throwable e) {
- addError(test, e);
- }
- }
- /**
- * Checks whether the test run should stop
- */
- public synchronized boolean shouldStop() {
- return fStop;
- }
- /**
- * Informs the result that a test will be started.
- */
- public void startTest(Test test) {
- final int count= test.countTestCases();
- synchronized(this) {
- fRunTests+= count;
- }
- for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
- ((TestListener)e.nextElement()).startTest(test);
- }
- }
- /**
- * Marks that the test run should stop.
- */
- public synchronized void stop() {
- fStop= true;
- }
- /**
- * Returns whether the entire test was successful or not.
- */
- public synchronized boolean wasSuccessful() {
- return failureCount() == 0 && errorCount() == 0;
- }
-}
diff --git a/junit/src/main/java/junit/framework/TestSuite.java b/junit/src/main/java/junit/framework/TestSuite.java
deleted file mode 100644
index d2df2b7..0000000
--- a/junit/src/main/java/junit/framework/TestSuite.java
+++ /dev/null
@@ -1,267 +0,0 @@
-package junit.framework;
-
-import java.util.Vector;
-import java.util.Enumeration;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.*;
-import java.lang.reflect.Constructor;
-
-/**
- * A <code>TestSuite</code> is a <code>Composite</code> of Tests.
- * It runs a collection of test cases. Here is an example using
- * the dynamic test definition.
- * <pre>
- * TestSuite suite= new TestSuite();
- * suite.addTest(new MathTest("testAdd"));
- * suite.addTest(new MathTest("testDivideByZero"));
- * </pre>
- * Alternatively, a TestSuite can extract the tests to be run automatically.
- * To do so you pass the class of your TestCase class to the
- * TestSuite constructor.
- * <pre>
- * TestSuite suite= new TestSuite(MathTest.class);
- * </pre>
- * This constructor creates a suite with all the methods
- * starting with "test" that take no arguments.
- *
- * @see Test
- */
-public class TestSuite implements Test {
-
- private Vector fTests= new Vector(10);
- private String fName;
-
- /**
- * Constructs an empty TestSuite.
- */
- public TestSuite() {
- }
-
- /**
- * Constructs a TestSuite from the given class with the given name.
- * @see TestSuite#TestSuite(Class)
- */
- public TestSuite(Class theClass, String name) {
- this(theClass);
- setName(name);
- }
-
- /**
- * Constructs a TestSuite from the given class. Adds all the methods
- * starting with "test" as test cases to the suite.
- * Parts of this method was written at 2337 meters in the Huffihutte,
- * Kanton Uri
- */
- public TestSuite(final Class theClass) {
- fName= theClass.getName();
- try {
- getTestConstructor(theClass); // Avoid generating multiple error messages
- } catch (NoSuchMethodException e) {
- addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"));
- return;
- }
-
- if (!Modifier.isPublic(theClass.getModifiers())) {
- addTest(warning("Class "+theClass.getName()+" is not public"));
- return;
- }
-
- Class superClass= theClass;
- Vector names= new Vector();
- while (Test.class.isAssignableFrom(superClass)) {
- Method[] methods= superClass.getDeclaredMethods();
- for (int i= 0; i < methods.length; i++) {
- addTestMethod(methods[i], names, theClass);
- }
- superClass= superClass.getSuperclass();
- }
- if (fTests.size() == 0)
- addTest(warning("No tests found in "+theClass.getName()));
- }
-
- /**
- * Constructs an empty TestSuite.
- */
- public TestSuite(String name) {
- setName(name);
- }
-
- /**
- * Adds a test to the suite.
- */
- public void addTest(Test test) {
- fTests.addElement(test);
- }
-
- /**
- * Adds the tests from the given class to the suite
- */
- public void addTestSuite(Class testClass) {
- addTest(new TestSuite(testClass));
- }
-
- private void addTestMethod(Method m, Vector names, Class theClass) {
- String name= m.getName();
- if (names.contains(name))
- return;
- if (! isPublicTestMethod(m)) {
- if (isTestMethod(m))
- addTest(warning("Test method isn't public: "+m.getName()));
- return;
- }
- names.addElement(name);
- addTest(createTest(theClass, name));
- }
-
- /**
- * ...as the moon sets over the early morning Merlin, Oregon
- * mountains, our intrepid adventurers type...
- */
- static public Test createTest(Class theClass, String name) {
- Constructor constructor;
- try {
- constructor= getTestConstructor(theClass);
- } catch (NoSuchMethodException e) {
- return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()");
- }
- Object test;
- try {
- if (constructor.getParameterTypes().length == 0) {
- test= constructor.newInstance(new Object[0]);
- if (test instanceof TestCase)
- ((TestCase) test).setName(name);
- } else {
- test= constructor.newInstance(new Object[]{name});
- }
- } catch (InstantiationException e) {
- return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
- } catch (InvocationTargetException e) {
- return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
- } catch (IllegalAccessException e) {
- return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
- }
- return (Test) test;
- }
-
- /**
- * Converts the stack trace into a string
- */
- private static String exceptionToString(Throwable t) {
- StringWriter stringWriter= new StringWriter();
- PrintWriter writer= new PrintWriter(stringWriter);
- t.printStackTrace(writer);
- return stringWriter.toString();
-
- }
-
- /**
- * Counts the number of test cases that will be run by this test.
- */
- public int countTestCases() {
- int count= 0;
- for (Enumeration e= tests(); e.hasMoreElements(); ) {
- Test test= (Test)e.nextElement();
- count= count + test.countTestCases();
- }
- return count;
- }
-
- /**
- * Gets a constructor which takes a single String as
- * its argument or a no arg constructor.
- */
- public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException {
- Class[] args= { String.class };
- try {
- return theClass.getConstructor(args);
- } catch (NoSuchMethodException e) {
- // fall through
- }
- return theClass.getConstructor(new Class[0]);
- }
-
- private boolean isPublicTestMethod(Method m) {
- return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
- }
-
- private boolean isTestMethod(Method m) {
- String name= m.getName();
- Class[] parameters= m.getParameterTypes();
- Class returnType= m.getReturnType();
- return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
- }
-
- /**
- * Runs the tests and collects their result in a TestResult.
- */
- public void run(TestResult result) {
- for (Enumeration e= tests(); e.hasMoreElements(); ) {
- if (result.shouldStop() )
- break;
- Test test= (Test)e.nextElement();
- runTest(test, result);
- }
- }
-
- public void runTest(Test test, TestResult result) {
- test.run(result);
- }
-
- /**
- * Returns the test at the given index
- */
- public Test testAt(int index) {
- return (Test)fTests.elementAt(index);
- }
-
- /**
- * Returns the number of tests in this suite
- */
- public int testCount() {
- return fTests.size();
- }
-
- /**
- * Returns the tests as an enumeration
- */
- public Enumeration tests() {
- return fTests.elements();
- }
-
- /**
- */
- public String toString() {
- if (getName() != null)
- return getName();
- return super.toString();
- }
-
- /**
- * Sets the name of the suite.
- * @param name The name to set
- */
- public void setName(String name) {
- fName= name;
- }
-
- /**
- * Returns the name of the suite. Not all
- * test suites have a name and this method
- * can return null.
- */
- public String getName() {
- return fName;
- }
-
- /**
- * Returns a test which will fail and log a warning message.
- */
- private static Test warning(final String message) {
- return new TestCase("warning") {
- protected void runTest() {
- fail(message);
- }
- };
- }
-}
diff --git a/junit/src/main/java/junit/framework/package.html b/junit/src/main/java/junit/framework/package.html
deleted file mode 100644
index 770d470..0000000
--- a/junit/src/main/java/junit/framework/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-The junit test framework.
-</BODY>
-</HTML>
diff --git a/luni/src/main/files/cacerts/7672ac4b.0 b/luni/src/main/files/cacerts/7672ac4b.0
new file mode 100644
index 0000000..addaae4
--- /dev/null
+++ b/luni/src/main/files/cacerts/7672ac4b.0
@@ -0,0 +1,123 @@
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET
+MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk
+BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4
+Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl
+cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0
+aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY
+F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N
+8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe
+rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K
+/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu
+7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC
+28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6
+lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E
+nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB
+0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09
+5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj
+WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN
+jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s
+ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM
+OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q
+619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn
+2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj
+o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v
+nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG
+5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq
+pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb
+dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0
+BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Autorit\xC3\xA9 Racine
+ Validity
+ Not Before: Sep 17 08:28:59 2008 GMT
+ Not After : Sep 17 08:28:59 2028 GMT
+ Subject: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Autorit\xC3\xA9 Racine
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (4096 bit)
+ Modulus (4096 bit):
+ 00:9d:85:9f:86:d3:e3:af:c7:b2:6b:6e:33:e0:9e:
+ b7:42:34:55:9d:f9:81:be:63:d8:23:76:0e:97:54:
+ cd:99:4c:1a:f1:39:c7:88:d8:17:50:0c:9e:61:da:
+ c0:4e:55:de:e7:5a:b8:7a:4e:77:87:0d:e5:b8:eb:
+ fa:9e:5e:7b:1e:c4:cf:28:74:c7:93:f5:14:c6:22:
+ 28:04:f9:91:c3:ab:27:73:6a:0e:2e:4d:f3:2e:28:
+ 1f:70:df:55:2f:4e:ed:c7:71:6f:09:72:2e:ed:d5:
+ 32:97:d0:f1:58:77:d1:60:bc:4e:5e:db:9a:84:f6:
+ 47:61:45:2b:f6:50:a6:7f:6a:71:27:48:84:35:9e:
+ ac:fe:69:a9:9e:7a:5e:35:25:fa:b4:a7:49:35:77:
+ 96:a7:36:5b:e1:cd:df:23:70:d8:5d:4c:a5:08:83:
+ f1:a6:24:38:13:a8:ec:2f:a8:a1:67:c7:a6:2d:86:
+ 47:ee:8a:fc:ec:9b:0e:74:f4:2b:49:02:7b:90:75:
+ 8c:fc:99:39:01:39:d6:4a:89:e5:9e:76:ab:3e:96:
+ 28:38:26:8b:dd:8d:8c:c0:f6:01:1e:6f:a5:31:12:
+ 38:7d:95:c2:71:ee:ed:74:ae:e4:36:a2:43:75:d5:
+ f1:00:9b:e2:e4:d7:cc:42:03:4b:78:7a:e5:7d:bb:
+ b8:ae:2e:20:93:d3:e4:61:df:71:e1:76:67:97:3f:
+ b6:df:6a:73:5a:64:22:e5:42:db:cf:81:03:93:d8:
+ f4:e3:10:e0:72:f6:00:70:ac:f0:c1:7a:0f:05:7f:
+ cf:34:69:45:b5:93:e4:19:db:52:16:23:05:89:0e:
+ 8d:48:e4:25:6f:b3:78:bf:62:f5:07:fa:95:24:c2:
+ 96:b2:e8:a3:23:c2:5d:03:fc:c3:d3:e5:7c:c9:75:
+ 23:d7:f4:f5:bc:de:e4:df:cd:80:bf:91:88:7d:a7:
+ 13:b4:39:ba:2c:ba:bd:d1:6b:cc:f3:a5:28:ed:44:
+ 9e:7d:52:a3:6f:96:2e:19:7e:1c:f3:5b:c7:16:8e:
+ bb:60:7d:77:66:47:54:82:00:11:60:6c:32:c1:a8:
+ 38:1b:eb:6e:98:13:d6:ee:38:f5:f0:9f:0e:ef:fe:
+ 31:81:c1:d2:24:95:2f:53:7a:69:a2:f0:0f:86:45:
+ 8e:58:82:2b:4c:22:d4:5e:a0:e7:7d:26:27:48:df:
+ 25:46:8d:4a:28:7c:86:9e:f9:9b:1a:59:b9:65:bf:
+ 05:dd:b6:42:5d:3d:e6:00:48:82:5e:20:f7:11:82:
+ de:ca:d8:9f:e6:37:47:26:1e:eb:78:f7:61:c3:41:
+ 64:58:02:41:f9:da:e0:d1:f8:f9:e8:fd:52:38:b6:
+ f5:89:df
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ 0D:8C:B6:61:DA:44:B8:D1:14:7D:C3:BE:7D:5E:48:F0:CE:CA:6A:B0
+ X509v3 Certificate Policies:
+ Policy: 1.2.250.1.86.2.2.0.1.1
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 24:3e:60:06:7e:1d:ef:3a:3e:db:ea:af:1c:9a:2c:01:0b:f4:
+ c5:b5:d9:49:31:f4:5d:41:8d:89:0c:4e:ff:6c:a2:fd:ff:e2:
+ 06:c8:39:9f:f1:5a:a9:dd:22:58:15:a8:8a:d3:b1:e6:32:09:
+ 82:03:6c:d7:3f:08:c7:f8:b9:ba:00:6d:b9:d6:fc:52:32:5d:
+ a4:7f:a4:31:94:bb:b6:4c:38:7f:28:30:35:ff:9f:23:53:b7:
+ b6:ee:14:70:00:40:2b:da:47:ab:34:7e:5e:a7:56:30:61:2b:
+ 8b:43:ac:fd:b6:88:28:f5:6b:b6:3e:60:4a:ba:42:90:34:67:
+ 8d:ea:eb:5f:45:54:3b:17:ac:8b:e4:c6:65:0f:ee:d0:8c:5d:
+ 66:39:ce:32:a7:d8:10:97:c0:7e:34:9c:9f:94:f3:f6:86:1f:
+ cf:1b:73:ad:94:79:87:68:70:c3:33:a5:70:e7:d8:d5:38:94:
+ 6f:63:79:eb:bf:0a:0e:08:e7:c5:2f:0f:42:a0:2b:14:40:ff:
+ 21:e0:05:c5:27:e1:84:11:13:ba:d6:86:1d:41:0b:13:23:89:
+ d3:c9:0b:e8:8a:ba:7a:a3:a3:73:37:35:80:7d:12:b8:33:77:
+ 40:38:c0:fa:5e:30:d2:f2:b6:a3:b1:d6:a2:95:97:81:9b:52:
+ ed:69:4c:ff:80:e4:53:db:54:5b:03:6d:54:5f:b1:b8:ef:24:
+ bd:6f:9f:11:c3:c7:64:c2:0f:28:62:85:66:5e:1a:7b:b2:b7:
+ ef:ae:35:c9:19:33:a8:b8:27:db:33:55:bf:68:e1:75:48:44:
+ 56:fb:cd:d3:48:bb:47:89:3a:ac:69:f5:80:c6:e4:44:50:2f:
+ 54:c4:aa:43:c5:31:31:58:bd:96:c5:ea:75:6c:9a:75:b1:4d:
+ f8:f7:97:ff:96:16:f2:97:4d:e8:f6:f3:11:f9:3a:7d:8a:38:
+ 6e:04:cb:e1:d3:45:15:aa:a5:d1:1d:9d:5d:63:e8:24:e6:36:
+ 14:e2:87:ad:1b:59:f5:44:9b:fb:d7:77:7c:1f:01:70:62:a1:
+ 20:1a:a2:c5:1a:28:f4:21:03:ee:2e:d9:c1:80:ea:b9:d9:82:
+ d6:5b:76:c2:cb:3b:b5:d2:00:f0:a3:0e:e1:ad:6e:40:f7:db:
+ a0:b4:d0:46:ae:15:d7:44:c2:4d:35:f9:d2:0b:f2:17:f6:ac:
+ 66:d5:24:b2:4f:d1:1c:99:c0:6e:f5:7d:eb:74:04:b8:f9:4d:
+ 77:09:d7:b4:cf:07:30:09:f1:b8:00:56:d9:17:16:16:0a:2b:
+ 86:df:8f:01:19:1a:e5:bb:82:63:ff:be:0b:76:16:5e:37:37:
+ e6:d8:74:97:a2:99:45:79
+SHA1 Fingerprint=2E:14:DA:EC:28:F0:FA:1E:8E:38:9A:4E:AB:EB:26:C0:0A:D3:83:C3
diff --git a/luni/src/main/files/cacerts/aeb67534.0 b/luni/src/main/files/cacerts/aeb67534.0
new file mode 100644
index 0000000..655f136
--- /dev/null
+++ b/luni/src/main/files/cacerts/aeb67534.0
@@ -0,0 +1,97 @@
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB
+8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy
+dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1
+YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3
+dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh
+IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD
+LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG
+EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g
+KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD
+ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu
+bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg
+ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R
+85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm
+4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV
+HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd
+QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t
+lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB
+o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4
+opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo
+dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW
+ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN
+AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y
+/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k
+SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy
+Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS
+Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl
+nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ (Negative)11:d4:c2:14:2b:de:21:eb:57:9d:53:fb:0c:22:3b:ff
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=ES, O=Agencia Catalana de Certificacio (NIF Q-0801176-I), OU=Serveis Publics de Certificacio, OU=Vegeu https://www.catcert.net/verarrel (c)03, OU=Jerarquia Entitats de Certificacio Catalanes, CN=EC-ACC
+ Validity
+ Not Before: Jan 7 23:00:00 2003 GMT
+ Not After : Jan 7 22:59:59 2031 GMT
+ Subject: C=ES, O=Agencia Catalana de Certificacio (NIF Q-0801176-I), OU=Serveis Publics de Certificacio, OU=Vegeu https://www.catcert.net/verarrel (c)03, OU=Jerarquia Entitats de Certificacio Catalanes, CN=EC-ACC
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:b3:22:c7:4f:e2:97:42:95:88:47:83:40:f6:1d:
+ 17:f3:83:73:24:1e:51:f3:98:8a:c3:92:b8:ff:40:
+ 90:05:70:87:60:c9:00:a9:b5:94:65:19:22:15:17:
+ c2:43:6c:66:44:9a:0d:04:3e:39:6f:a5:4b:7a:aa:
+ 63:b7:8a:44:9d:d9:63:91:84:66:e0:28:0f:ba:42:
+ e3:6e:8e:f7:14:27:93:69:ee:91:0e:a3:5f:0e:b1:
+ eb:66:a2:72:4f:12:13:86:65:7a:3e:db:4f:07:f4:
+ a7:09:60:da:3a:42:99:c7:b2:7f:b3:16:95:1c:c7:
+ f9:34:b5:94:85:d5:99:5e:a0:48:a0:7e:e7:17:65:
+ b8:a2:75:b8:1e:f3:e5:42:7d:af:ed:f3:8a:48:64:
+ 5d:82:14:93:d8:c0:e4:ff:b3:50:72:f2:76:f6:b3:
+ 5d:42:50:79:d0:94:3e:6b:0c:00:be:d8:6b:0e:4e:
+ 2a:ec:3e:d2:cc:82:a2:18:65:33:13:77:9e:9a:5d:
+ 1a:13:d8:c3:db:3d:c8:97:7a:ee:70:ed:a7:e6:7c:
+ db:71:cf:2d:94:62:df:6d:d6:f5:38:be:3f:a5:85:
+ 0a:19:b8:a8:d8:09:75:42:70:c4:ea:ef:cb:0e:c8:
+ 34:a8:12:22:98:0c:b8:13:94:b6:4b:ec:f0:d0:90:
+ e7:27
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ email:ec_acc@catcert.net
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Key Identifier:
+ A0:C3:8B:44:AA:37:A5:45:BF:97:80:5A:D1:F1:78:A2:9B:E9:5D:8D
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.15096.1.3.1.10
+ CPS: https://www.catcert.net/verarrel
+ User Notice:
+ Explicit Text: Vegeu https://www.catcert.net/verarrel
+
+ Signature Algorithm: sha1WithRSAEncryption
+ a0:48:5b:82:01:f6:4d:48:b8:39:55:35:9c:80:7a:53:99:d5:
+ 5a:ff:b1:71:3b:cc:39:09:94:5e:d6:da:ef:be:01:5b:5d:d3:
+ 1e:d8:fd:7d:4f:cd:a0:41:e0:34:93:bf:cb:e2:86:9c:37:92:
+ 90:56:1c:dc:eb:29:05:e5:c4:9e:c7:35:df:8a:0c:cd:c5:21:
+ 43:e9:aa:88:e5:35:c0:19:42:63:5a:02:5e:a4:48:18:3a:85:
+ 6f:dc:9d:bc:3f:9d:9c:c1:87:b8:7a:61:08:e9:77:0b:7f:70:
+ ab:7a:dd:d9:97:2c:64:1e:85:bf:bc:74:96:a1:c3:7a:12:ec:
+ 0c:1a:6e:83:0c:3c:e8:72:46:9f:fb:48:d5:5e:97:e6:b1:a1:
+ f8:e4:ef:46:25:94:9c:89:db:69:38:be:ec:5c:0e:56:c7:65:
+ 51:e5:50:88:88:bf:42:d5:2b:3d:e5:f9:ba:9e:2e:b3:ca:f4:
+ 73:92:02:0b:be:4c:66:eb:20:fe:b9:cb:b5:99:7f:e6:b6:13:
+ fa:ca:4b:4d:d9:ee:53:46:06:3b:c6:4e:ad:93:5a:81:7e:6c:
+ 2a:4b:6a:05:45:8c:f2:21:a4:31:90:87:6c:65:9c:9d:a5:60:
+ 95:3a:52:7f:f5:d1:ab:08:6e:f3:ee:5b:f9:88:3d:7e:b8:6f:
+ 6e:03:e4:42
+SHA1 Fingerprint=28:90:3A:63:5B:52:80:FA:E6:77:4C:0B:6D:A7:D6:BA:A6:4A:F2:E8
diff --git a/luni/src/main/files/cacerts/c33a80d4.0 b/luni/src/main/files/cacerts/c33a80d4.0
index c76b601..5744b48 100644
--- a/luni/src/main/files/cacerts/c33a80d4.0
+++ b/luni/src/main/files/cacerts/c33a80d4.0
@@ -1,31 +1,33 @@
-----BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
-dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
-MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
-MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
-A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
-b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
-cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
-VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
-ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
-uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
-9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
-pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+MIIDNjCCAp+gAwIBAgIQNhIilsXjOKUgodJfTNcJVDANBgkqhkiG9w0BAQUFADCB
+zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
+Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
+CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh
+d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
+cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVow
+gc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcT
+CUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNV
+BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRo
+YXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1z
+ZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
+aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560
+ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j
++ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBlkKyID1bZ5jA01CbH0FDxkt5r1DmI
+CSLGpmODA/eZd9iy5Ri4XWPz1HP7bJyZePFLeH0ZJMMrAoT4vCLZiiLXoPxx7JGH
+IPG47LHlVYCsPVLIOQ7C8MAFT9aCdYy9X9LcdpoFEsmvcsPcJX6kTY4XpeCHf+Ga
+WuFg3GQjPEIuTQ==
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: md5WithRSAEncryption
+ Serial Number:
+ 36:12:22:96:c5:e3:38:a5:20:a1:d2:5f:4c:d7:09:54
+ Signature Algorithm: sha1WithRSAEncryption
Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
Validity
Not Before: Aug 1 00:00:00 1996 GMT
- Not After : Dec 31 23:59:59 2020 GMT
+ Not After : Jan 1 23:59:59 2021 GMT
Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -44,13 +46,13 @@
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
- Signature Algorithm: md5WithRSAEncryption
- 26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7:
- c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5:
- 08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb:
- c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59:
- 6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9:
- a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92:
- 32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07:
- 14:42
-SHA1 Fingerprint=62:7F:8D:78:27:65:63:99:D2:7D:7F:90:44:C9:FE:B3:F3:3E:FA:9A
+ Signature Algorithm: sha1WithRSAEncryption
+ 65:90:ac:88:0f:56:d9:e6:30:34:d4:26:c7:d0:50:f1:92:de:
+ 6b:d4:39:88:09:22:c6:a6:63:83:03:f7:99:77:d8:b2:e5:18:
+ b8:5d:63:f3:d4:73:fb:6c:9c:99:78:f1:4b:78:7d:19:24:c3:
+ 2b:02:84:f8:bc:22:d9:8a:22:d7:a0:fc:71:ec:91:87:20:f1:
+ b8:ec:b1:e5:55:80:ac:3d:52:c8:39:0e:c2:f0:c0:05:4f:d6:
+ 82:75:8c:bd:5f:d2:dc:76:9a:05:12:c9:af:72:c3:dc:25:7e:
+ a4:4d:8e:17:a5:e0:87:7f:e1:9a:5a:e1:60:dc:64:23:3c:42:
+ 2e:4d
+SHA1 Fingerprint=E0:AB:05:94:20:72:54:93:05:60:62:02:36:70:F7:CD:2E:FC:66:66
diff --git a/luni/src/main/files/cacerts/c3a6a9ad.0 b/luni/src/main/files/cacerts/c3a6a9ad.0
new file mode 100644
index 0000000..b0b3360
--- /dev/null
+++ b/luni/src/main/files/cacerts/c3a6a9ad.0
@@ -0,0 +1,80 @@
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R
+dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw
+MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy
+dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52
+ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM
+EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj
+lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ
+znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH
+2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1
+k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs
+2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD
+VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG
+KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+
+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R
+FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE
+DNuxUCAKGkq6ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 93214 (0x16c1e)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=AT, O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH, OU=A-Trust-nQual-03, CN=A-Trust-nQual-03
+ Validity
+ Not Before: Aug 17 22:00:00 2005 GMT
+ Not After : Aug 17 22:00:00 2015 GMT
+ Subject: C=AT, O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH, OU=A-Trust-nQual-03, CN=A-Trust-nQual-03
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:ad:3d:61:6e:03:f3:90:3b:c0:41:0b:84:80:cd:
+ ec:2a:a3:9d:6b:bb:6e:c2:42:84:f7:51:14:e1:a0:
+ a8:2d:51:a3:51:f2:de:23:f0:34:44:ff:94:eb:cc:
+ 05:23:95:40:b9:07:78:a5:25:f6:0a:bd:45:86:e8:
+ d9:bd:c0:04:8e:85:44:61:ef:7f:a7:c9:fa:c1:25:
+ cc:85:2c:63:3f:05:60:73:49:05:e0:60:78:95:10:
+ 4b:dc:f9:11:59:ce:71:7f:40:9b:8a:aa:24:df:0b:
+ 42:e2:db:56:bc:4a:d2:a5:0c:9b:b7:43:3e:dd:83:
+ d3:26:10:02:cf:ea:23:c4:49:4e:e5:d3:e9:b4:88:
+ ab:0c:ae:62:92:d4:65:87:d9:6a:d7:f4:85:9f:e4:
+ 33:22:25:a5:e5:c8:33:ba:c3:c7:41:dc:5f:c6:6a:
+ cc:00:0e:6d:32:a8:b6:87:36:00:62:77:9b:1e:1f:
+ 34:cb:90:3c:78:88:74:05:eb:79:f5:93:71:65:ca:
+ 9d:c7:6b:18:2d:3d:5c:4e:e7:d5:f8:3f:31:7d:8f:
+ 87:ec:0a:22:2f:23:e9:fe:bb:7d:c9:e0:f4:ec:eb:
+ 7c:c4:b0:c3:2d:62:b5:9a:71:d6:b1:6a:e8:ec:d9:
+ ed:d5:72:ec:be:57:01:ce:05:55:9f:de:d1:60:88:
+ 10:b3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 44:6A:95:67:55:79:11:4F
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha1WithRSAEncryption
+ 55:d4:54:d1:59:48:5c:b3:93:85:aa:bf:63:2f:e4:80:ce:34:
+ a3:34:62:3e:f6:d8:ee:67:88:31:04:03:6f:0b:d4:07:fb:4e:
+ 75:0f:d3:2e:d3:c0:17:c7:c6:28:ec:06:0d:11:24:0e:0e:a5:
+ 5d:bf:8c:b2:13:96:71:dc:d4:ce:0e:0d:0a:68:32:6c:b9:41:
+ 31:19:ab:b1:07:7b:4d:98:d3:5c:b0:d1:f0:a7:42:a0:b5:c4:
+ 8e:af:fe:f1:3f:f4:ef:4f:46:00:76:eb:02:fb:f9:9d:d2:40:
+ 96:c7:88:3a:b8:9f:11:79:f3:80:65:a8:bd:1f:d3:78:81:a0:
+ 51:4c:37:b4:a6:5d:25:70:d1:66:c9:68:f9:2e:11:14:68:f1:
+ 54:98:08:ac:26:92:0f:de:89:9e:d4:fa:b3:79:2b:d2:a3:79:
+ d4:ec:8b:ac:87:53:68:42:4c:51:51:74:1e:1b:27:2e:e3:f5:
+ 1f:29:74:4d:ed:af:f7:e1:92:99:81:e8:be:3a:c7:17:50:f6:
+ b7:c6:fc:9b:b0:8a:6b:d6:88:03:91:8f:06:77:3a:85:02:dd:
+ 98:d5:43:78:3f:c6:30:15:ac:9b:6b:cb:57:b7:89:51:8b:3a:
+ e8:c9:84:0c:db:b1:50:20:0a:1a:4a:ba:6a:1a:bd:ec:1b:c8:
+ c5:84:9a:cd
+SHA1 Fingerprint=D3:C0:63:F2:19:ED:07:3E:34:AD:5D:75:0B:32:76:29:FF:D5:9A:F2
diff --git a/luni/src/main/files/cacerts/d59297b8.0 b/luni/src/main/files/cacerts/d59297b8.0
new file mode 100644
index 0000000..0bb1e6d
--- /dev/null
+++ b/luni/src/main/files/cacerts/d59297b8.0
@@ -0,0 +1,78 @@
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
+DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy
+dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj
+YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV
+OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr
+zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM
+VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ
+hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO
+ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw
+awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs
+OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF
+coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc
+okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8
+t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
+1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
+SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2
+ Validity
+ Not Before: May 29 05:00:39 2009 GMT
+ Not After : May 29 05:00:39 2029 GMT
+ Subject: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:d0:15:39:52:b1:52:b3:ba:c5:59:82:c4:5d:52:
+ ae:3a:43:65:80:4b:c7:f2:96:bc:db:36:97:d6:a6:
+ 64:8c:a8:5e:f0:e3:0a:1c:f7:df:97:3d:4b:ae:f6:
+ 5d:ec:21:b5:41:ab:cd:b9:7e:76:9f:be:f9:3e:36:
+ 34:a0:3b:c1:f6:31:11:45:74:93:3d:57:80:c5:f9:
+ 89:99:ca:e5:ab:6a:d4:b5:da:41:90:10:c1:d6:d6:
+ 42:89:c2:bf:f4:38:12:95:4c:54:05:f7:36:e4:45:
+ 83:7b:14:65:d6:dc:0c:4d:d1:de:7e:0c:ab:3b:c4:
+ 15:be:3a:56:a6:5a:6f:76:69:52:a9:7a:b9:c8:eb:
+ 6a:9a:5d:52:d0:2d:0a:6b:35:16:09:10:84:d0:6a:
+ ca:3a:06:00:37:47:e4:7e:57:4f:3f:8b:eb:67:b8:
+ 88:aa:c5:be:53:55:b2:91:c4:7d:b9:b0:85:19:06:
+ 78:2e:db:61:1a:fa:85:f5:4a:91:a1:e7:16:d5:8e:
+ a2:39:df:94:b8:70:1f:28:3f:8b:fc:40:5e:63:83:
+ 3c:83:2a:1a:99:6b:cf:de:59:6a:3b:fc:6f:16:d7:
+ 1f:fd:4a:10:eb:4e:82:16:3a:ac:27:0c:53:f1:ad:
+ d5:24:b0:6b:03:50:c1:2d:3c:16:dd:44:34:27:1a:
+ 75:fb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0A:85:A9:77:65:05:98:7C:40:81:F8:0F:97:2C:38:F1:0A:EC:3C:CF
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 4c:3a:a3:44:ac:b9:45:b1:c7:93:7e:c8:0b:0a:42:df:64:ea:
+ 1c:ee:59:6c:08:ba:89:5f:6a:ca:4a:95:9e:7a:8f:07:c5:da:
+ 45:72:82:71:0e:3a:d2:cc:6f:a7:b4:a1:23:bb:f6:24:9f:cb:
+ 17:fe:8c:a6:ce:c2:d2:db:cc:8d:fc:71:fc:03:29:c1:6c:5d:
+ 33:5f:64:b6:65:3b:89:6f:18:76:78:f5:dc:a2:48:1f:19:3f:
+ 8e:93:eb:f1:fa:17:ee:cd:4e:e3:04:12:55:d6:e5:e4:dd:fb:
+ 3e:05:7c:e2:1d:5e:c6:a7:bc:97:4f:68:3a:f5:e9:2e:0a:43:
+ b6:af:57:5c:62:68:7c:b7:fd:a3:8a:84:a0:ac:62:be:2b:09:
+ 87:34:f0:6a:01:bb:9b:29:56:3c:fe:00:37:cf:23:6c:f1:4e:
+ aa:b6:74:46:12:6c:91:ee:34:d5:ec:9a:91:e7:44:be:90:31:
+ 72:d5:49:02:f6:02:e5:f4:1f:eb:7c:d9:96:55:a9:ff:ec:8a:
+ f9:99:47:ff:35:5a:02:aa:04:cb:8a:5b:87:71:29:91:bd:a4:
+ b4:7a:0d:bd:9a:f5:57:23:00:07:21:17:3f:4a:39:d1:05:49:
+ 0b:a7:b6:37:81:a5:5d:8c:aa:33:5e:81:28:7c:a7:7d:27:eb:
+ 00:ae:8d:37
+SHA1 Fingerprint=5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74
diff --git a/luni/src/main/files/cacerts/ddc328ff.0 b/luni/src/main/files/cacerts/ddc328ff.0
index 0cd9896..8a6d14f 100644
--- a/luni/src/main/files/cacerts/ddc328ff.0
+++ b/luni/src/main/files/cacerts/ddc328ff.0
@@ -1,31 +1,32 @@
-----BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
-MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
-MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
-DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
-dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
-cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
-DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
-gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
-yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
-L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
-EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
-7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
-QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
-qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+MIIDIjCCAougAwIBAgIQNKT/9jCvTKU8MxdCoZRmdTANBgkqhkiG9w0BAQUFADCB
+xDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
+Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
+CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhh
+d3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
+ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBxDELMAkGA1UE
+BhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZl
+ciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
+/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF
+/rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982
+OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF
+BQADgYEAvkBpQW/G28GnvwfAReTQtUMeTJUzNelewj4o9qgNUNX/4gwP/FACjq6R
+ua00io2fJ3GqGcxL6ATK1BdrEhrWxl/WzV7/iXa/2EjYWb0IiokdV81FHlK6EpqE
++hiJX+j5MDVqAWC5mYCDhQpu2vTJj15zLTFKY6B08h+LItIpPus=
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: md5WithRSAEncryption
+ Serial Number:
+ 34:a4:ff:f6:30:af:4c:a5:3c:33:17:42:a1:94:66:75
+ Signature Algorithm: sha1WithRSAEncryption
Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
Validity
Not Before: Aug 1 00:00:00 1996 GMT
- Not After : Dec 31 23:59:59 2020 GMT
+ Not After : Jan 1 23:59:59 2021 GMT
Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -44,13 +45,13 @@
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
- Signature Algorithm: md5WithRSAEncryption
- 07:fa:4c:69:5c:fb:95:cc:46:ee:85:83:4d:21:30:8e:ca:d9:
- a8:6f:49:1a:e6:da:51:e3:60:70:6c:84:61:11:a1:1a:c8:48:
- 3e:59:43:7d:4f:95:3d:a1:8b:b7:0b:62:98:7a:75:8a:dd:88:
- 4e:4e:9e:40:db:a8:cc:32:74:b9:6f:0d:c6:e3:b3:44:0b:d9:
- 8a:6f:9a:29:9b:99:18:28:3b:d1:e3:40:28:9a:5a:3c:d5:b5:
- e7:20:1b:8b:ca:a4:ab:8d:e9:51:d9:e2:4c:2c:59:a9:da:b9:
- b2:75:1b:f6:42:f2:ef:c7:f2:18:f9:89:bc:a3:ff:8a:23:2e:
- 70:47
-SHA1 Fingerprint=23:E5:94:94:51:95:F2:41:48:03:B4:D5:64:D2:A3:A3:F5:D8:8B:8C
+ Signature Algorithm: sha1WithRSAEncryption
+ be:40:69:41:6f:c6:db:c1:a7:bf:07:c0:45:e4:d0:b5:43:1e:
+ 4c:95:33:35:e9:5e:c2:3e:28:f6:a8:0d:50:d5:ff:e2:0c:0f:
+ fc:50:02:8e:ae:91:b9:ad:34:8a:8d:9f:27:71:aa:19:cc:4b:
+ e8:04:ca:d4:17:6b:12:1a:d6:c6:5f:d6:cd:5e:ff:89:76:bf:
+ d8:48:d8:59:bd:08:8a:89:1d:57:cd:45:1e:52:ba:12:9a:84:
+ fa:18:89:5f:e8:f9:30:35:6a:01:60:b9:99:80:83:85:0a:6e:
+ da:f4:c9:8f:5e:73:2d:31:4a:63:a0:74:f2:1f:8b:22:d2:29:
+ 3e:eb
+SHA1 Fingerprint=9F:AD:91:A6:CE:6A:C6:C5:00:47:C4:4E:C9:D4:A5:0D:92:D8:49:79
diff --git a/luni/src/main/files/cacerts/fb126c6d.0 b/luni/src/main/files/cacerts/fb126c6d.0
new file mode 100644
index 0000000..8200caa
--- /dev/null
+++ b/luni/src/main/files/cacerts/fb126c6d.0
@@ -0,0 +1,106 @@
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJF
+UzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJ
+R1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcN
+MDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3WjBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScw
+JQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+
+WmmmO3I2F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKj
+SgbwJ/BXufjpTjJ3Cj9BZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGl
+u6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQD0EbtFpKd71ng+CT516nDOeB0/RSrFOy
+A8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXteJajCq+TA81yc477OMUxk
+Hl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMBAAGjggM7
+MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBr
+aS5ndmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIIC
+IwYKKwYBBAG/VQIBADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8A
+cgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIA
+YQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIAYQBsAGkAdABhAHQAIABWAGEA
+bABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQByAGEAYwBpAPMA
+bgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMA
+aQBvAG4AYQBtAGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQA
+ZQAgAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEA
+YwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBuAHQAcgBhACAAZQBuACAAbABhACAA
+ZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcA
+LgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0dHA6
+Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+y
+eAT8MIGVBgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQsw
+CQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0G
+A1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVu
+Y2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRhTvW1yEICKrNcda3Fbcrn
+lD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdzCkj+IHLt
+b8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg
+9J63NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XF
+ducTZnV+ZfsBn5OHiJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmC
+IoaZM3Fa6hlXPZHNqcCjbgcTpsnt+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 994436456 (0x3b45e568)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=ES, O=Generalitat Valenciana, OU=PKIGVA, CN=Root CA Generalitat Valenciana
+ Validity
+ Not Before: Jul 6 16:22:47 2001 GMT
+ Not After : Jul 1 15:22:47 2021 GMT
+ Subject: C=ES, O=Generalitat Valenciana, OU=PKIGVA, CN=Root CA Generalitat Valenciana
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c6:2a:ab:57:11:37:2f:22:8a:ca:03:74:1d:ca:
+ ed:2d:a2:0b:bc:33:52:40:26:47:be:5a:69:a6:3b:
+ 72:36:17:4c:e8:df:b8:bb:2f:76:e1:40:46:74:65:
+ 02:90:52:08:b4:ff:a8:8c:c1:e0:c7:89:56:10:39:
+ 33:ef:68:b4:5f:5f:da:6d:23:a1:89:5e:22:a3:4a:
+ 06:f0:27:f0:57:b9:f8:e9:4e:32:77:0a:3f:41:64:
+ f3:eb:65:ee:76:fe:54:aa:7d:1d:20:ae:f3:d7:74:
+ c2:0a:5f:f5:08:28:52:08:cc:55:5d:d2:0f:db:9a:
+ 81:a5:bb:a1:b3:c1:94:cd:54:e0:32:75:31:91:1a:
+ 62:b2:de:75:e2:cf:4f:89:d9:91:90:0f:41:1b:b4:
+ 5a:4a:77:bd:67:83:e0:93:e7:5e:a7:0c:e7:81:d3:
+ f4:52:ac:53:b2:03:c7:44:26:fb:79:e5:cb:34:60:
+ 50:10:7b:1b:db:6b:d7:47:ab:5f:7c:68:ca:6e:9d:
+ 41:03:10:ee:6b:99:7b:5e:25:a8:c2:ab:e4:c0:f3:
+ 5c:9c:e3:be:ce:31:4c:64:1e:5e:80:a2:f5:83:7e:
+ 0c:d6:ca:8c:55:8e:be:e0:be:49:07:0f:a3:24:41:
+ 7a:58:1d:84:ea:58:12:c8:e1:b7:ed:ef:93:de:94:
+ 08:31
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ Authority Information Access:
+ OCSP - URI:http://ocsp.pki.gva.es
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:2
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.8149.2.1.0
+ User Notice:
+ Explicit Text:
+ CPS: http://www.pki.gva.es/cps
+
+ X509v3 Subject Key Identifier:
+ 7B:35:D3:40:D2:1C:78:19:66:EF:74:10:28:DC:3E:4F:B2:78:04:FC
+ X509v3 Authority Key Identifier:
+ keyid:7B:35:D3:40:D2:1C:78:19:66:EF:74:10:28:DC:3E:4F:B2:78:04:FC
+ DirName:/C=ES/O=Generalitat Valenciana/OU=PKIGVA/CN=Root CA Generalitat Valenciana
+ serial:3B:45:E5:68
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 24:61:4e:f5:b5:c8:42:02:2a:b3:5c:75:ad:c5:6d:ca:e7:94:
+ 3f:a5:68:95:88:c1:54:c0:10:69:a2:12:2f:18:3f:25:50:a8:
+ 7c:4a:ea:c6:09:d9:f4:75:c6:40:da:af:50:9d:3d:a5:16:bb:
+ 6d:31:c6:c7:73:0a:48:fe:20:72:ed:6f:cc:e8:83:61:16:46:
+ 90:01:95:4b:7d:8e:9a:52:09:2f:f6:6f:1c:e4:a1:71:cf:8c:
+ 2a:5a:17:73:83:47:4d:0f:36:fb:04:4d:49:51:e2:14:c9:64:
+ 61:fb:d4:14:e0:f4:9e:b7:34:8f:0a:26:bd:97:5c:f4:79:3a:
+ 4a:30:19:cc:ad:4f:a0:98:8a:b4:31:97:2a:e2:73:6d:7e:78:
+ b8:f8:88:89:4f:b1:22:91:64:4b:f5:50:de:03:db:e5:c5:76:
+ e7:13:66:75:7e:65:fb:01:9f:93:87:88:9d:f9:46:57:7c:4d:
+ 60:af:98:73:13:23:a4:20:91:81:fa:d0:61:66:b8:7d:d1:af:
+ d6:6f:1e:6c:3d:e9:11:fd:a9:f9:82:22:86:99:33:71:5a:ea:
+ 19:57:3d:91:cd:a9:c0:a3:6e:07:13:a6:c9:ed:f8:68:a3:9e:
+ c3:5a:72:09:87:28:d1:c4:73:c4:73:18:5f:50:75:16:31:9f:
+ b7:e8:7c:c3
+SHA1 Fingerprint=A0:73:E5:C5:BD:43:61:0D:86:4C:21:13:0A:85:58:57:CC:9C:EA:46
diff --git a/luni/src/main/java/java/io/ObjectInputStream.java b/luni/src/main/java/java/io/ObjectInputStream.java
index d3af278..4541f1b 100644
--- a/luni/src/main/java/java/io/ObjectInputStream.java
+++ b/luni/src/main/java/java/io/ObjectInputStream.java
@@ -1618,9 +1618,13 @@
throw corruptStream(tc);
}
- Enum<?> result = Enum.valueOf((Class) classDesc.forClass(), name);
+ Enum<?> result;
+ try {
+ result = Enum.valueOf((Class) classDesc.forClass(), name);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidObjectException(e.getMessage());
+ }
registerObjectRead(result, newHandle, unshared);
-
return result;
}
diff --git a/luni/src/main/java/java/io/Serializable.java b/luni/src/main/java/java/io/Serializable.java
index 9cd7816..f1256bb 100644
--- a/luni/src/main/java/java/io/Serializable.java
+++ b/luni/src/main/java/java/io/Serializable.java
@@ -18,20 +18,83 @@
package java.io;
/**
- * An empty marker interface for classes that want to support serialization and
- * deserialization based on the {@code ObjectOutputStream} and {@code
- * ObjectInputStream} classes. Implementing this interface is enough to make
- * most classes serializable. If a class needs more fine-grained control over
- * the serialization process (for example to implement compatibility with older
- * versions of the class), it can achieve this by providing the following two
- * methods (signatures must match exactly):
- * <p>
- * {@code private void writeObject(java.io.ObjectOutputStream out) throws
- * IOException}
- * <p>
- * {@code private void readObject(java.io.ObjectInputStream in) throws
- * IOException, ClassNotFoundException}
+ * Marks classes that can be serialized by {@link ObjectOutputStream} and
+ * deserialized by {@link ObjectInputStream}.
+ *
+ * <p><strong>Warning:</strong> this interface limits how its implementing
+ * classes can change in the future. By implementing {@code Serializable} you
+ * expose your flexible in-memory implementation details as a rigid binary
+ * representation. Simple code changes--like renaming private fields--are
+ * not safe when the changed class is serializable.
+ *
+ * <h3>The Serialized Form</h3>
+ * By default, the serialization mechanism encodes an object's class name, the
+ * names of its non-transient fields (including non-public fields), and the
+ * values of all of those fields. The output is an opaque sequence of bytes.
+ * Those bytes can be decoded into a new, equivalent instance as long as the
+ * decoder has compatible versions of the originating classes.
+ *
+ * <p>Changing the class name, field names or field types breaks serialization
+ * compatibility and complicates interoperability between old and new versions
+ * of the serializable class. Adding or removing fields also complicates
+ * serialization between versions of a class because it requires your code to
+ * cope with missing fields.
+ *
+ * <p>Every serializable class is assigned a version identifier called a {@code
+ * serialVersionUID}. By default, this identifier is computed by hashing the
+ * class declaration and its members. This identifier is included in the
+ * serialized form so that version conflicts can be detected during
+ * deserialization. If the local {@code serialVersionUID} differs from the
+ * {@code serialVersionUID} in the serialized data, deserialization will fail
+ * with an {@link InvalidClassException}.
+ *
+ * <p>You can avoid this failure by declaring an explicit {@code
+ * serialVersionUID}. Declaring an explicit {@code serialVersionUID} tells the
+ * serialization mechanism that the class is forward and backward compatible
+ * with all versions that share that {@code serialVersionUID}. Declaring a
+ * {@code serialVersionUID} looks like this: <pre> {@code
+ *
+ * private static final long serialVersionUID = 0L;
+ * }</pre>
+ * If you declare a {@code serialVersionUID}, you should increment it each
+ * time your class changes incompatibly with the previous version. Typically
+ * this is when you add, change or remove a non-transient field.
+ *
+ * <p>You can take control of your serialized form by implementing these two
+ * methods with these exact signatures in your serializable classes:
+ * <pre> {@code
+ *
+ * private void writeObject(java.io.ObjectOutputStream out)
+ * throws IOException {
+ * // write 'this' to 'out'...
+ * }
+ *
+ * private void readObject(java.io.ObjectInputStream in)
+ * throws IOException, ClassNotFoundException {
+ * // populate the fields of 'this' from the data in 'in'...
+ * }
+ * }</pre>
+ * It is impossible to maintain serialization compatibility across a class name
+ * change. For this reason, implementing {@code Serializable} in anonymous
+ * inner classes is highly discouraged: simply reordering the members in the
+ * file could change the generated class name and break serialization
+ * compatibility.
+ *
+ * <p>You can exclude member fields from serialization by giving them the {@code
+ * transient} modifier. Upon deserialization, the transient field's value will
+ * be null, 0, or false according to its type.
+ *
+ * <h3>Implement Serializable Judiciously</h3>
+ * Refer to <i>Effective Java</i>'s chapter on serialization for thorough
+ * coverage of the serialization API. The book explains how to use this
+ * interface without harming your application's maintainability.
+ *
+ * <h3>Recommended Alternatives</h3>
+ * <strong>JSON</strong> is concise, human-readable and efficient. Android
+ * includes both a {@link android.util.JsonReader streaming API} and a {@link
+ * org.json.JSONObject tree API} to read and write JSON. Use a binding library
+ * like <a href="http://code.google.com/p/google-gson/">GSON</a> to read and
+ * write Java objects directly.
*/
public interface Serializable {
- /* empty */
}
diff --git a/luni/src/main/java/java/lang/AssertionError.java b/luni/src/main/java/java/lang/AssertionError.java
index 3d0d2a4..077e57c 100644
--- a/luni/src/main/java/java/lang/AssertionError.java
+++ b/luni/src/main/java/java/lang/AssertionError.java
@@ -52,8 +52,10 @@
* optionally the cause.
*/
public AssertionError(Object detailMessage) {
- super(String.valueOf(detailMessage),
- (detailMessage instanceof Throwable ? (Throwable) detailMessage : null));
+ super(String.valueOf(detailMessage));
+ if (detailMessage instanceof Throwable) {
+ initCause((Throwable) detailMessage);
+ }
}
/**
diff --git a/luni/src/main/java/java/lang/Daemons.java b/luni/src/main/java/java/lang/Daemons.java
index 88d4d93..a7d0964 100644
--- a/luni/src/main/java/java/lang/Daemons.java
+++ b/luni/src/main/java/java/lang/Daemons.java
@@ -58,7 +58,8 @@
if (thread != null) {
throw new IllegalStateException("already running");
}
- thread = new Thread(this, getClass().getSimpleName());
+ thread = new Thread(ThreadGroup.mSystem, this,
+ getClass().getSimpleName());
thread.setDaemon(true);
thread.start();
}
@@ -179,6 +180,9 @@
try {
finalizingStartedNanos = System.nanoTime();
finalizingObject = object;
+ synchronized (FinalizerWatchdogDaemon.INSTANCE) {
+ FinalizerWatchdogDaemon.INSTANCE.notify();
+ }
object.finalize();
} catch (Throwable ex) {
// The RI silently swallows these, but Android has always logged.
@@ -199,37 +203,40 @@
@Override public void run() {
while (isRunning()) {
- Object object = FinalizerDaemon.INSTANCE.finalizingObject;
- long startedNanos = FinalizerDaemon.INSTANCE.finalizingStartedNanos;
+ try {
+ Object object = FinalizerDaemon.INSTANCE.finalizingObject;
+ long startedNanos = FinalizerDaemon.INSTANCE.finalizingStartedNanos;
- long sleepMillis = MAX_FINALIZE_MILLIS;
- if (object != null) {
+ if (object == null) {
+ synchronized (this) {
+ // wait until something is being finalized
+ // http://code.google.com/p/android/issues/detail?id=22778
+ wait();
+ continue;
+ }
+ }
+
long elapsedMillis = (System.nanoTime() - startedNanos) / NANOS_PER_MILLI;
- sleepMillis -= elapsedMillis;
- }
-
- if (sleepMillis > 0) {
- try {
+ long sleepMillis = MAX_FINALIZE_MILLIS - elapsedMillis;
+ if (sleepMillis > 0) {
Thread.sleep(sleepMillis);
- } catch (InterruptedException e) {
+ elapsedMillis = (System.nanoTime() - startedNanos) / NANOS_PER_MILLI;
+ }
+
+ if (object != FinalizerDaemon.INSTANCE.finalizingObject
+ || VMRuntime.getRuntime().isDebuggerActive()) {
continue;
}
- }
- if (object == null
- || object != FinalizerDaemon.INSTANCE.finalizingObject
- || VMRuntime.getRuntime().isDebuggerActive()) {
- continue;
+ // The current object has exceeded the finalization deadline; abort!
+ Exception syntheticException = new TimeoutException();
+ syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
+ System.logE(object.getClass().getName() + ".finalize() timed out after "
+ + elapsedMillis + " ms; limit is " + MAX_FINALIZE_MILLIS + " ms",
+ syntheticException);
+ System.exit(2);
+ } catch (InterruptedException ignored) {
}
-
- // The current object has exceeded the finalization deadline; abort!
- long elapsedMillis = (System.nanoTime() - startedNanos) / NANOS_PER_MILLI;
- Exception syntheticException = new TimeoutException();
- syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
- System.logE(object.getClass().getName() + ".finalize() timed out after "
- + elapsedMillis + " ms; limit is " + MAX_FINALIZE_MILLIS + " ms",
- syntheticException);
- System.exit(2);
}
}
}
diff --git a/luni/src/main/java/java/lang/ProcessManager.java b/luni/src/main/java/java/lang/ProcessManager.java
index c480185..1e820a9 100644
--- a/luni/src/main/java/java/lang/ProcessManager.java
+++ b/luni/src/main/java/java/lang/ProcessManager.java
@@ -253,11 +253,17 @@
}
public void destroy() {
- try {
- Libcore.os.kill(pid, SIGKILL);
- } catch (ErrnoException e) {
- System.logI("Failed to destroy process " + pid, e);
+ // If the process hasn't already exited, send it SIGKILL.
+ synchronized (exitValueMutex) {
+ if (exitValue == null) {
+ try {
+ Libcore.os.kill(pid, SIGKILL);
+ } catch (ErrnoException e) {
+ System.logI("Failed to destroy process " + pid, e);
+ }
+ }
}
+ // Close any open streams.
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(errorStream);
IoUtils.closeQuietly(outputStream);
@@ -266,10 +272,8 @@
public int exitValue() {
synchronized (exitValueMutex) {
if (exitValue == null) {
- throw new IllegalThreadStateException(
- "Process has not yet terminated.");
+ throw new IllegalThreadStateException("Process has not yet terminated: " + pid);
}
-
return exitValue;
}
}
diff --git a/luni/src/main/java/java/lang/Runtime.java b/luni/src/main/java/java/lang/Runtime.java
index b3a0796..320f157 100644
--- a/luni/src/main/java/java/lang/Runtime.java
+++ b/luni/src/main/java/java/lang/Runtime.java
@@ -284,7 +284,7 @@
}
// Get out of here finally...
- nativeExit(code, true);
+ nativeExit(code);
}
}
}
@@ -393,7 +393,7 @@
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}
- private static native void nativeExit(int code, boolean isExit);
+ private static native void nativeExit(int code);
private static native String nativeLoad(String filename, ClassLoader loader);
@@ -595,7 +595,7 @@
*/
public void halt(int code) {
// Get out of here...
- nativeExit(code, false);
+ nativeExit(code);
}
/**
diff --git a/luni/src/main/java/java/lang/System.java b/luni/src/main/java/java/lang/System.java
index f452186..de99161 100644
--- a/luni/src/main/java/java/lang/System.java
+++ b/luni/src/main/java/java/lang/System.java
@@ -616,7 +616,8 @@
*
* <p>Security managers do <i>not</i> provide a secure environment for
* executing untrusted code and are unsupported on Android. Untrusted code
- * cannot be safely isolated within a single VM on Android.
+ * cannot be safely isolated within a single VM on Android, so this method
+ * <i>always</i> throws a {@code SecurityException}.
*
* @param sm a security manager
* @throws SecurityException always
diff --git a/luni/src/main/java/java/lang/ref/SoftReference.java b/luni/src/main/java/java/lang/ref/SoftReference.java
index 8880171..12c3491 100644
--- a/luni/src/main/java/java/lang/ref/SoftReference.java
+++ b/luni/src/main/java/java/lang/ref/SoftReference.java
@@ -33,56 +33,47 @@
package java.lang.ref;
/**
- * Implements a soft reference, which is the least-weak of the three types of
- * references. Once the garbage collector has decided that an object {@code obj}
- * is softly-reachable, the following
- * may happen, either immediately or at a later point:
+ * A reference that is cleared when its referent is not strongly reachable and
+ * there is memory pressure.
*
+ * <h3>Avoid Soft References for Caching</h3>
+ * In practice, soft references are inefficient for caching. The runtime doesn't
+ * have enough information on which references to clear and which to keep. Most
+ * fatally, it doesn't know what to do when given the choice between clearing a
+ * soft reference and growing the heap.
+ *
+ * <p>The lack of information on the value to your application of each reference
+ * limits the usefulness of soft references. References that are cleared too
+ * early cause unnecessary work; those that are cleared too late waste memory.
+ *
+ * <p>Most applications should use an {@code android.util.LruCache} instead of
+ * soft references. LruCache has an effective eviction policy and lets the user
+ * tune how much memory is allotted.
+ *
+ * <h3>Garbage Collection of Soft References</h3>
+ * When the garbage collector encounters an object {@code obj} that is
+ * softly-reachable, the following happens:
* <ul>
- * <li>
- * A set {@code ref} of references is determined. {@code ref} contains the
- * following elements:
- * <ul>
- * <li>
- * All soft references pointing to {@code obj}.
- * </li>
- * <li>
- * All soft references pointing to objects from which {@code obj} is
- * strongly reachable.
- * </li>
- * </ul>
+ * <li>A set {@code refs} of references is determined. {@code refs} contains
+ * the following elements:
+ * <ul>
+ * <li>All soft references pointing to {@code obj}.</li>
+ * <li>All soft references pointing to objects from which {@code obj} is
+ * strongly reachable.</li>
+ * </ul>
* </li>
- * <li>
- * All references in {@code ref} are atomically cleared.
- * </li>
- * <li>
- * At the same time or some time in the future, all references in {@code
- * ref} will be enqueued with their corresponding reference queues, if any.
- * </li>
+ * <li>All references in {@code refs} are atomically cleared.</li>
+ * <li>At the same time or some time in the future, all references in {@code
+ * refs} will be enqueued with their corresponding reference queues, if
+ * any.</li>
* </ul>
+ * The system may delay clearing and enqueueing soft references, yet all {@code
+ * SoftReference}s pointing to softly reachable objects will be cleared before
+ * the runtime throws an {@link OutOfMemoryError}.
*
- * The system may decide not to clear and enqueue soft references until a later
- * time, yet all {@code SoftReference}s pointing to softly reachable objects are
- * guaranteed to be cleared before the VM will throw an {@link
- * java.lang.OutOfMemoryError}.
- *
- * Soft references are useful for caches that should automatically have
- * their entries removed once they are not referenced any more (from outside),
- * and there is a need for memory. The difference between a {@code
- * SoftReference} and a {@code WeakReference} is the point of time at which the
- * decision is made to clear and enqueue the reference:
- *
- * <ul>
- * <li>
- * A {@code SoftReference} should be cleared and enqueued <em>as late as
- * possible</em>, that is, in case the VM is in danger of running out of
- * memory.
- * </li>
- * <li>
- * A {@code WeakReference} may be cleared and enqueued as soon as is
- * known to be weakly-referenced.
- * </li>
- * </ul>
+ * <p>Unlike a {@code WeakReference}, a {@code SoftReference} will not be
+ * cleared and enqueued until the runtime must reclaim memory to satisfy an
+ * allocation.
*/
public class SoftReference<T> extends Reference<T> {
diff --git a/luni/src/main/java/java/lang/reflect/AccessibleObject.java b/luni/src/main/java/java/lang/reflect/AccessibleObject.java
index 6dde0c2..9c6b8c7 100644
--- a/luni/src/main/java/java/lang/reflect/AccessibleObject.java
+++ b/luni/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -183,10 +183,10 @@
StringBuilder result = new StringBuilder();
if (types.length != 0) {
- result.append(types[0].getName());
+ appendTypeName(result, types[0]);
for (int i = 1; i < types.length; i++) {
result.append(',');
- result.append(types[i].getName());
+ appendTypeName(result, types[i]);
}
}
@@ -228,23 +228,21 @@
private static native Object[] getClassSignatureAnnotation(Class clazz);
/**
- * Appends the specified class name to the buffer. The class may represent
- * a simple type, a reference type or an array type.
- *
- * @param sb buffer
- * @param obj the class which name should be appended to the buffer
- *
- * @throws NullPointerException if any of the arguments is null
+ * Appends the best {@link #toString} name for {@code c} to {@code out}.
+ * This works around the fact that {@link Class#getName} is lousy for
+ * primitive arrays (it writes "[C" instead of "char[]") and {@link
+ * Class#getCanonicalName()} is lousy for nested classes (it uses a "."
+ * separator rather than a "$" separator).
*/
- void appendArrayType(StringBuilder sb, Class<?> obj) {
+ void appendTypeName(StringBuilder out, Class<?> c) {
int dimensions = 0;
- while (obj.isArray()) {
- obj = obj.getComponentType();
+ while (c.isArray()) {
+ c = c.getComponentType();
dimensions++;
}
- sb.append(obj.getName());
+ out.append(c.getName());
for (int d = 0; d < dimensions; d++) {
- sb.append("[]");
+ out.append("[]");
}
}
diff --git a/luni/src/main/java/java/lang/reflect/Array.java b/luni/src/main/java/java/lang/reflect/Array.java
index 3ecfae0..088a434 100644
--- a/luni/src/main/java/java/lang/reflect/Array.java
+++ b/luni/src/main/java/java/lang/reflect/Array.java
@@ -33,446 +33,343 @@
package java.lang.reflect;
/**
- * This class provides static methods to create and access arrays dynamically.
+ * Provides static methods to create and access arrays dynamically.
*/
public final class Array {
+ private Array() {
+ }
- /**
- * Prevent this class from being instantiated.
- */
- private Array(){
- //do nothing
+ private static IllegalArgumentException notAnArray(Object o) {
+ throw new IllegalArgumentException("Not an array: " + o.getClass());
+ }
+
+ private static IllegalArgumentException incompatibleType(Object o) {
+ throw new IllegalArgumentException("Array has incompatible type: " + o.getClass());
+ }
+
+ private static RuntimeException badArray(Object array) {
+ if (array == null) {
+ throw new NullPointerException("array == null");
+ } else if (!array.getClass().isArray()) {
+ throw notAnArray(array);
+ } else {
+ throw incompatibleType(array);
+ }
}
/**
- * Returns the element of the array at the specified index. This reproduces
- * the effect of {@code array[index]}. If the array component is a primitive
- * type, the result is automatically boxed.
+ * Returns the element of the array at the specified index. Equivalent to {@code array[index]}.
+ * If the array component is a primitive type, the result is automatically boxed.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element, possibly boxed
- *
- * @throws NullPointerException
- * if the array is null
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static Object get(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof Object[])
+ public static Object get(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof Object[]) {
return ((Object[]) array)[index];
-
- if (array instanceof boolean[])
+ }
+ if (array instanceof boolean[]) {
return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
-
- if (array instanceof byte[])
+ }
+ if (array instanceof byte[]) {
return Byte.valueOf(((byte[]) array)[index]);
-
- if (array instanceof char[])
+ }
+ if (array instanceof char[]) {
return Character.valueOf(((char[]) array)[index]);
-
- if (array instanceof short[])
+ }
+ if (array instanceof short[]) {
return Short.valueOf(((short[]) array)[index]);
-
- if (array instanceof int[])
+ }
+ if (array instanceof int[]) {
return Integer.valueOf(((int[]) array)[index]);
-
- if (array instanceof long[])
+ }
+ if (array instanceof long[]) {
return Long.valueOf(((long[]) array)[index]);
-
- if (array instanceof float[])
+ }
+ if (array instanceof float[]) {
return new Float(((float[]) array)[index]);
-
- if (array instanceof double[])
+ }
+ if (array instanceof double[]) {
return new Double(((double[]) array)[index]);
-
- if (array == null)
- throw new NullPointerException();
-
- throw new IllegalArgumentException("Not an array");
+ }
+ if (array == null) {
+ throw new NullPointerException("array == null");
+ }
+ throw notAnArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code boolean}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the boolean at the given index in the given boolean array.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static boolean getBoolean(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static boolean getBoolean(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof boolean[]) {
return ((boolean[]) array)[index];
- } else if (array == null) {
- throw new NullPointerException();
- } else if (array.getClass().isArray()) {
- throw new IllegalArgumentException("Wrong array type");
- } else {
- throw new IllegalArgumentException("Not an array");
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code byte}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the byte at the given index in the given byte array.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static byte getByte(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static byte getByte(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof byte[]) {
return ((byte[]) array)[index];
- } else {
- return getBoolean(array, index) ? (byte)1 : (byte)0;
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code char}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the char at the given index in the given char array.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static char getChar(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static char getChar(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof char[]) {
return ((char[]) array)[index];
- } else if (array == null) {
- throw new NullPointerException();
- } else if (array.getClass().isArray()) {
- throw new IllegalArgumentException("Wrong array type");
- } else {
- throw new IllegalArgumentException("Not an array");
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code double}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the double at the given index in the given array.
+ * Applies to byte, char, float, double, int, long, and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static double getDouble(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static double getDouble(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof double[]) {
return ((double[]) array)[index];
- } else {
- return getFloat(array, index);
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array)[index];
+ } else if (array instanceof char[]) {
+ return ((char[]) array)[index];
+ } else if (array instanceof float[]) {
+ return ((float[]) array)[index];
+ } else if (array instanceof int[]) {
+ return ((int[]) array)[index];
+ } else if (array instanceof long[]) {
+ return ((long[]) array)[index];
+ } else if (array instanceof short[]) {
+ return ((short[]) array)[index];
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code float}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the float at the given index in the given array.
+ * Applies to byte, char, float, int, long, and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static float getFloat(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static float getFloat(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof float[]) {
return ((float[]) array)[index];
- } else {
- return getLong(array, index);
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array)[index];
+ } else if (array instanceof char[]) {
+ return ((char[]) array)[index];
+ } else if (array instanceof int[]) {
+ return ((int[]) array)[index];
+ } else if (array instanceof long[]) {
+ return ((long[]) array)[index];
+ } else if (array instanceof short[]) {
+ return ((short[]) array)[index];
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to an
- * {@code int}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the int at the given index in the given array.
+ * Applies to byte, char, int, and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static int getInt(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static int getInt(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof int[]) {
return ((int[]) array)[index];
- } else {
- return getShort(array, index);
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array)[index];
+ } else if (array instanceof char[]) {
+ return ((char[]) array)[index];
+ } else if (array instanceof short[]) {
+ return ((short[]) array)[index];
}
+ throw badArray(array);
}
/**
- * Returns the length of the array. This reproduces the effect of {@code
- * array.length}
+ * Returns the length of the array. Equivalent to {@code array.length}.
*
- * @param array
- * the array
- *
- * @return the length of the array
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array
*/
public static int getLength(Object array) {
- if (array instanceof Object[])
+ if (array instanceof Object[]) {
return ((Object[]) array).length;
-
- if (array instanceof boolean[])
+ } else if (array instanceof boolean[]) {
return ((boolean[]) array).length;
-
- if (array instanceof byte[])
+ } else if (array instanceof byte[]) {
return ((byte[]) array).length;
-
- if (array instanceof char[])
+ } else if (array instanceof char[]) {
return ((char[]) array).length;
-
- if (array instanceof short[])
- return ((short[]) array).length;
-
- if (array instanceof int[])
- return ((int[]) array).length;
-
- if (array instanceof long[])
- return ((long[]) array).length;
-
- if (array instanceof float[])
- return ((float[]) array).length;
-
- if (array instanceof double[])
+ } else if (array instanceof double[]) {
return ((double[]) array).length;
-
- if (array == null)
- throw new NullPointerException();
-
- throw new IllegalArgumentException("Not an array");
- }
+ } else if (array instanceof float[]) {
+ return ((float[]) array).length;
+ } else if (array instanceof int[]) {
+ return ((int[]) array).length;
+ } else if (array instanceof long[]) {
+ return ((long[]) array).length;
+ } else if (array instanceof short[]) {
+ return ((short[]) array).length;
+ }
+ throw badArray(array);
+ }
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code long}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the long at the given index in the given array.
+ * Applies to byte, char, int, long, and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static long getLong(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static long getLong(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof long[]) {
return ((long[]) array)[index];
- } else {
- return getInt(array, index);
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array)[index];
+ } else if (array instanceof char[]) {
+ return ((char[]) array)[index];
+ } else if (array instanceof int[]) {
+ return ((int[]) array)[index];
+ } else if (array instanceof short[]) {
+ return ((short[]) array)[index];
}
+ throw badArray(array);
}
/**
- * Returns the element of the array at the specified index, converted to a
- * {@code short}, if possible. This reproduces the effect of {@code
- * array[index]}
+ * Returns the short at the given index in the given array.
+ * Applies to byte and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- *
- * @return the requested element
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the element at the
* index position can not be converted to the return type
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static short getShort(Object array, int index)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof short[])
+ public static short getShort(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof short[]) {
return ((short[]) array)[index];
-
- return getByte(array, index);
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array)[index];
+ }
+ throw badArray(array);
}
/**
* Returns a new multidimensional array of the specified component type and
- * dimensions. This reproduces the effect of {@code new
- * componentType[d0][d1]...[dn]} for a dimensions array of { d0, d1, ... ,
- * dn }.
+ * dimensions. Equivalent to {@code new componentType[d0][d1]...[dn]} for a
+ * dimensions array of { d0, d1, ... , dn }.
*
- * @param componentType
- * the component type of the new array
- * @param dimensions
- * the dimensions of the new array
- *
- * @return the new array
- *
- * @throws NullPointerException
- * if the component type is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws NegativeArraySizeException
* if any of the dimensions are negative
* @throws IllegalArgumentException
* if the array of dimensions is of size zero, or exceeds the
* limit of the number of dimension for an array (currently 255)
*/
- public static Object newInstance(Class<?> componentType, int... dimensions)
- throws NegativeArraySizeException, IllegalArgumentException {
- if (dimensions.length <= 0 || dimensions.length > 255)
- throw new IllegalArgumentException("Bad number of dimensions");
-
- if (componentType == void.class)
- throw new IllegalArgumentException();
-
- if (componentType == null)
- throw new NullPointerException();
-
+ public static Object newInstance(Class<?> componentType, int... dimensions) throws NegativeArraySizeException, IllegalArgumentException {
+ if (dimensions.length <= 0 || dimensions.length > 255) {
+ throw new IllegalArgumentException("Bad number of dimensions: " + dimensions.length);
+ }
+ if (componentType == void.class) {
+ throw new IllegalArgumentException("Can't allocate an array of void");
+ }
+ if (componentType == null) {
+ throw new NullPointerException("componentType == null");
+ }
return createMultiArray(componentType, dimensions);
}
/*
* Create a multi-dimensional array of objects with the specified type.
*/
- native private static Object createMultiArray(Class<?> componentType,
- int[] dimensions) throws NegativeArraySizeException;
+ private static native Object createMultiArray(Class<?> componentType, int[] dimensions) throws NegativeArraySizeException;
/**
- * Returns a new array of the specified component type and length. This
- * reproduces the effect of {@code new componentType[size]}.
- *
- * @param componentType
- * the component type of the new array
- * @param size
- * the length of the new array
- *
- * @return the new array
+ * Returns a new array of the specified component type and length.
+ * Equivalent to {@code new componentType[size]}.
*
* @throws NullPointerException
* if the component type is null
* @throws NegativeArraySizeException
* if {@code size < 0}
*/
- public static Object newInstance(Class<?> componentType, int size)
- throws NegativeArraySizeException {
+ public static Object newInstance(Class<?> componentType, int size) throws NegativeArraySizeException {
if (!componentType.isPrimitive()) {
return createObjectArray(componentType, size);
- }
- if (componentType == boolean.class) {
+ } else if (componentType == boolean.class) {
return new boolean[size];
- }
- if (componentType == byte.class) {
+ } else if (componentType == byte.class) {
return new byte[size];
- }
- if (componentType == char.class) {
+ } else if (componentType == char.class) {
return new char[size];
- }
- if (componentType == short.class) {
+ } else if (componentType == short.class) {
return new short[size];
- }
- if (componentType == int.class) {
+ } else if (componentType == int.class) {
return new int[size];
- }
- if (componentType == long.class) {
+ } else if (componentType == long.class) {
return new long[size];
- }
- if (componentType == float.class) {
+ } else if (componentType == float.class) {
return new float[size];
- }
- if (componentType == double.class) {
+ } else if (componentType == double.class) {
return new double[size];
- }
- if (componentType == void.class) {
- throw new IllegalArgumentException();
+ } else if (componentType == void.class) {
+ throw new IllegalArgumentException("Can't allocate an array of void");
}
throw new AssertionError();
}
@@ -480,81 +377,58 @@
/*
* Create a one-dimensional array of objects with the specified type.
*/
- native private static Object createObjectArray(Class<?> componentType,
- int length) throws NegativeArraySizeException;
+ private static native Object createObjectArray(Class<?> componentType, int length) throws NegativeArraySizeException;
/**
- * Sets the element of the array at the specified index to the value. This
- * reproduces the effect of {@code array[index] = value}. If the array
+ * Sets the element of the array at the specified index to the value.
+ * Equivalent to {@code array[index] = value}. If the array
* component is a primitive type, the value is automatically unboxed.
*
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if {@code array} is not an array or the value cannot be
* converted to the array type by a widening conversion
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static void set(Object array, int index, Object value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static void set(Object array, int index, Object value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (!array.getClass().isArray()) {
- throw new IllegalArgumentException("Not an array type");
+ throw notAnArray(array);
}
if (array instanceof Object[]) {
- if (value != null &&
- !array.getClass().getComponentType().isInstance(value)) {
- // incompatible object type for this array
- throw new IllegalArgumentException("Wrong array type");
+ if (value != null && !array.getClass().getComponentType().isInstance(value)) {
+ throw incompatibleType(array);
}
-
((Object[]) array)[index] = value;
} else {
if (value == null) {
throw new IllegalArgumentException("Primitive array can't take null values.");
}
-
- if (value instanceof Boolean)
+ if (value instanceof Boolean) {
setBoolean(array, index, ((Boolean) value).booleanValue());
- else if (value instanceof Byte)
+ } else if (value instanceof Byte) {
setByte(array, index, ((Byte) value).byteValue());
- else if (value instanceof Character)
+ } else if (value instanceof Character) {
setChar(array, index, ((Character) value).charValue());
- else if (value instanceof Short)
+ } else if (value instanceof Short) {
setShort(array, index, ((Short) value).shortValue());
- else if (value instanceof Integer)
+ } else if (value instanceof Integer) {
setInt(array, index, ((Integer) value).intValue());
- else if (value instanceof Long)
+ } else if (value instanceof Long) {
setLong(array, index, ((Long) value).longValue());
- else if (value instanceof Float)
+ } else if (value instanceof Float) {
setFloat(array, index, ((Float) value).floatValue());
- else if (value instanceof Double)
+ } else if (value instanceof Double) {
setDouble(array, index, ((Double) value).doubleValue());
+ }
}
}
/**
- * Sets the element of the array at the specified index to the {@code
- * boolean} value. This reproduces the effect of {@code array[index] =
- * value}.
+ * Sets {@code array[index] = value}. Applies to boolean arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if the {@code array} is not an array or the value cannot be
* converted to the array type by a widening conversion
@@ -565,212 +439,171 @@
if (array instanceof boolean[]) {
((boolean[]) array)[index] = value;
} else {
- setByte(array, index, value ? (byte)1 : (byte)0);
+ throw badArray(array);
}
}
/**
- * Sets the element of the array at the specified index to the {@code byte}
- * value. This reproduces the effect of {@code array[index] = value}.
+ * Sets {@code array[index] = value}. Applies to byte, double, float, int, long, and short arrays.
*
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
+ * @throws NullPointerException if {@code array == null}
* @throws IllegalArgumentException
* if the {@code array} is not an array or the value cannot be
* converted to the array type by a widening conversion
* @throws ArrayIndexOutOfBoundsException
* if {@code index < 0 || index >= array.length}
*/
- public static void setByte(Object array, int index, byte value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ public static void setByte(Object array, int index, byte value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
if (array instanceof byte[]) {
((byte[]) array)[index] = value;
- } else {
- setShort(array, index, value);
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code char}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setChar(Object array, int index, char value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof char[]) {
- ((char[]) array)[index] = value;
- } else if (array == null) {
- throw new NullPointerException();
- } else if (!array.getClass().isArray()) {
- throw new IllegalArgumentException("Not an array");
- } else {
- throw new IllegalArgumentException("Wrong array type");
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code double}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setDouble(Object array, int index, double value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof double[]) {
+ } else if (array instanceof double[]) {
((double[]) array)[index] = value;
- } else if (array == null) {
- throw new NullPointerException();
- } else if (!array.getClass().isArray()) {
- throw new IllegalArgumentException("Not an array");
- } else {
- throw new IllegalArgumentException("Wrong array type");
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code float}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setFloat(Object array, int index, float value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof float[]) {
+ } else if (array instanceof float[]) {
((float[]) array)[index] = value;
- } else {
- setDouble(array, index, value);
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code int}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setInt(Object array, int index, int value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof int[]) {
+ } else if (array instanceof int[]) {
((int[]) array)[index] = value;
- } else {
- setLong(array, index, value);
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code long}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setLong(Object array, int index, long value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof long[]) {
+ } else if (array instanceof long[]) {
((long[]) array)[index] = value;
- } else {
- setFloat(array, index, value);
- }
- }
-
- /**
- * Set the element of the array at the specified index to the {@code short}
- * value. This reproduces the effect of {@code array[index] = value}.
- *
- * @param array
- * the array
- * @param index
- * the index
- * @param value
- * the new value
- *
- * @throws NullPointerException
- * if the {@code array} is {@code null}
- * @throws IllegalArgumentException
- * if the {@code array} is not an array or the value cannot be
- * converted to the array type by a widening conversion
- * @throws ArrayIndexOutOfBoundsException
- * if {@code index < 0 || index >= array.length}
- */
- public static void setShort(Object array, int index, short value)
- throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
- if (array instanceof short[]) {
+ } else if (array instanceof short[]) {
((short[]) array)[index] = value;
} else {
- setInt(array, index, value);
+ throw badArray(array);
}
}
+ /**
+ * Sets {@code array[index] = value}. Applies to char, double, float, int, and long arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setChar(Object array, int index, char value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof char[]) {
+ ((char[]) array)[index] = value;
+ } else if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else if (array instanceof float[]) {
+ ((float[]) array)[index] = value;
+ } else if (array instanceof int[]) {
+ ((int[]) array)[index] = value;
+ } else if (array instanceof long[]) {
+ ((long[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
+
+ /**
+ * Sets {@code array[index] = value}. Applies to double arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setDouble(Object array, int index, double value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
+
+ /**
+ * Sets {@code array[index] = value}. Applies to double and float arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setFloat(Object array, int index, float value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof float[]) {
+ ((float[]) array)[index] = value;
+ } else if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
+
+ /**
+ * Sets {@code array[index] = value}. Applies to double, float, int, and long arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setInt(Object array, int index, int value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof int[]) {
+ ((int[]) array)[index] = value;
+ } else if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else if (array instanceof float[]) {
+ ((float[]) array)[index] = value;
+ } else if (array instanceof long[]) {
+ ((long[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
+
+ /**
+ * Sets {@code array[index] = value}. Applies to double, float, and long arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setLong(Object array, int index, long value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof long[]) {
+ ((long[]) array)[index] = value;
+ } else if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else if (array instanceof float[]) {
+ ((float[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
+
+ /**
+ * Sets {@code array[index] = value}. Applies to double, float, int, long, and short arrays.
+ *
+ * @throws NullPointerException if {@code array == null}
+ * @throws IllegalArgumentException
+ * if the {@code array} is not an array or the value cannot be
+ * converted to the array type by a widening conversion
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code index < 0 || index >= array.length}
+ */
+ public static void setShort(Object array, int index, short value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+ if (array instanceof short[]) {
+ ((short[]) array)[index] = value;
+ } else if (array instanceof double[]) {
+ ((double[]) array)[index] = value;
+ } else if (array instanceof float[]) {
+ ((float[]) array)[index] = value;
+ } else if (array instanceof int[]) {
+ ((int[]) array)[index] = value;
+ } else if (array instanceof long[]) {
+ ((long[]) array)[index] = value;
+ } else {
+ throw badArray(array);
+ }
+ }
}
diff --git a/luni/src/main/java/java/lang/reflect/Constructor.java b/luni/src/main/java/java/lang/reflect/Constructor.java
index b03e28b..9a0e03c 100644
--- a/luni/src/main/java/java/lang/reflect/Constructor.java
+++ b/luni/src/main/java/java/lang/reflect/Constructor.java
@@ -142,7 +142,7 @@
sb.append("> ");
}
// append constructor name
- appendArrayType(sb, getDeclaringClass());
+ appendTypeName(sb, getDeclaringClass());
// append parameters
sb.append('(');
appendArrayGenericType(sb,
diff --git a/luni/src/main/java/java/lang/reflect/Field.java b/luni/src/main/java/java/lang/reflect/Field.java
index 87c955a..0aacb11 100644
--- a/luni/src/main/java/java/lang/reflect/Field.java
+++ b/luni/src/main/java/java/lang/reflect/Field.java
@@ -869,9 +869,9 @@
if (result.length() != 0) {
result.append(' ');
}
- appendArrayType(result, type);
+ appendTypeName(result, type);
result.append(' ');
- result.append(declaringClass.getName());
+ appendTypeName(result, declaringClass);
result.append('.');
result.append(name);
return result.toString();
diff --git a/luni/src/main/java/java/lang/reflect/Method.java b/luni/src/main/java/java/lang/reflect/Method.java
index 8a9c0f1..044dbff9 100644
--- a/luni/src/main/java/java/lang/reflect/Method.java
+++ b/luni/src/main/java/java/lang/reflect/Method.java
@@ -188,7 +188,7 @@
appendGenericType(sb, Types.getType(genericReturnType));
sb.append(' ');
// append method name
- appendArrayType(sb, getDeclaringClass());
+ appendTypeName(sb, getDeclaringClass());
sb.append(".").append(getName());
// append parameters
sb.append('(');
diff --git a/luni/src/main/java/java/net/AddressCache.java b/luni/src/main/java/java/net/AddressCache.java
index 08f5d81..194761a 100644
--- a/luni/src/main/java/java/net/AddressCache.java
+++ b/luni/src/main/java/java/net/AddressCache.java
@@ -21,18 +21,20 @@
/**
* Implements caching for {@code InetAddress}. We use a unified cache for both positive and negative
* cache entries.
+ *
+ * TODO: benchmark and optimize InetAddress until we get to the point where we can just rely on
+ * the C library level caching. The main thing caching at this level buys us is avoiding repeated
+ * conversions from 'struct sockaddr's to InetAddress[].
*/
class AddressCache {
/**
* When the cache contains more entries than this, we start dropping the oldest ones.
* This should be a power of two to avoid wasted space in our custom map.
*/
- private static final int MAX_ENTRIES = 512;
+ private static final int MAX_ENTRIES = 16;
- // Default time-to-live for positive cache entries. 600 seconds (10 minutes).
- private static final long DEFAULT_POSITIVE_TTL_NANOS = 600 * 1000000000L;
- // Default time-to-live for negative cache entries. 10 seconds.
- private static final long DEFAULT_NEGATIVE_TTL_NANOS = 10 * 1000000000L;
+ // The TTL for the Java-level cache is short, just 2s.
+ private static final long TTL_NANOS = 2 * 1000000000L;
// The actual cache.
private final BasicLruCache<String, AddressCacheEntry> cache
@@ -47,13 +49,13 @@
* The absolute expiry time in nanoseconds. Nanoseconds from System.nanoTime is ideal
* because -- unlike System.currentTimeMillis -- it can never go backwards.
*
- * Unless we need to cope with DNS TTLs of 292 years, we don't need to worry about overflow.
+ * We don't need to worry about overflow with a TTL_NANOS of 2s.
*/
final long expiryNanos;
- AddressCacheEntry(Object value, long expiryNanos) {
+ AddressCacheEntry(Object value) {
this.value = value;
- this.expiryNanos = expiryNanos;
+ this.expiryNanos = System.nanoTime() + TTL_NANOS;
}
}
@@ -85,28 +87,7 @@
* certain length of time.
*/
public void put(String hostname, InetAddress[] addresses) {
- put(hostname, addresses, true);
- }
-
- /**
- * Associates the given 'detailMessage' with 'hostname'. The association will expire after a
- * certain length of time.
- */
- public void put(String hostname, String detailMessage) {
- put(hostname, detailMessage, false);
- }
-
- /**
- * Associates the given 'addresses' with 'hostname'. The association will expire after a
- * certain length of time.
- */
- public void put(String hostname, Object value, boolean isPositive) {
- // Calculate the expiry time.
- String propertyName = isPositive ? "networkaddress.cache.ttl" : "networkaddress.cache.negative.ttl";
- long defaultTtlNanos = isPositive ? DEFAULT_POSITIVE_TTL_NANOS : DEFAULT_NEGATIVE_TTL_NANOS;
- long expiryNanos = System.nanoTime() + defaultTtlNanos;
- // Update the cache.
- cache.put(hostname, new AddressCacheEntry(value, expiryNanos));
+ cache.put(hostname, new AddressCacheEntry(addresses));
}
/**
@@ -114,26 +95,6 @@
* negative cache entry.)
*/
public void putUnknownHost(String hostname, String detailMessage) {
- put(hostname, detailMessage);
- }
-
- private long customTtl(String propertyName, long defaultTtlNanos) {
- String ttlString = System.getProperty(propertyName, null);
- if (ttlString == null) {
- return System.nanoTime() + defaultTtlNanos;
- }
- try {
- long ttlS = Long.parseLong(ttlString);
- // For the system properties, -1 means "cache forever" and 0 means "don't cache".
- if (ttlS == -1) {
- return Long.MAX_VALUE;
- } else if (ttlS == 0) {
- return Long.MIN_VALUE;
- } else {
- return System.nanoTime() + ttlS * 1000000000L;
- }
- } catch (NumberFormatException ex) {
- return System.nanoTime() + defaultTtlNanos;
- }
+ cache.put(hostname, new AddressCacheEntry(detailMessage));
}
}
diff --git a/luni/src/main/java/java/net/Authenticator.java b/luni/src/main/java/java/net/Authenticator.java
index fc66c89..a68784a 100644
--- a/luni/src/main/java/java/net/Authenticator.java
+++ b/luni/src/main/java/java/net/Authenticator.java
@@ -33,27 +33,13 @@
// the default authenticator that needs to be set
private static Authenticator thisAuthenticator;
- private static final NetPermission requestPasswordAuthenticationPermission = new NetPermission(
- "requestPasswordAuthentication");
-
- private static final NetPermission setDefaultAuthenticatorPermission = new NetPermission(
- "setDefaultAuthenticator");
-
- // the requester connection info
private String host;
-
private InetAddress addr;
-
private int port;
-
private String protocol;
-
private String prompt;
-
private String scheme;
-
private URL url;
-
private RequestorType rt;
/**
diff --git a/luni/src/main/java/java/net/ExtendedResponseCache.java b/luni/src/main/java/java/net/ExtendedResponseCache.java
new file mode 100644
index 0000000..a70e734
--- /dev/null
+++ b/luni/src/main/java/java/net/ExtendedResponseCache.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 java.net;
+
+/**
+ * A response cache that supports statistics tracking and updating stored
+ * responses. Implementations of {@link ResponseCache} should implement this
+ * interface to receive additional support from the HTTP engine.
+ *
+ * @hide
+ */
+public interface ExtendedResponseCache {
+
+ /*
+ * This hidden interface is defined in a non-hidden package (java.net) so
+ * its @hide tag will be parsed by Doclava. This hides this interface from
+ * implementing classes' documentation.
+ */
+
+ /**
+ * Track an HTTP response being satisfied by {@code source}.
+ * @hide
+ */
+ void trackResponse(ResponseSource source);
+
+ /**
+ * Track an conditional GET that was satisfied by this cache.
+ * @hide
+ */
+ void trackConditionalCacheHit();
+
+ /**
+ * Updates stored HTTP headers using a hit on a conditional GET.
+ * @hide
+ */
+ void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection);
+}
diff --git a/luni/src/main/java/java/net/HttpURLConnection.java b/luni/src/main/java/java/net/HttpURLConnection.java
index a54e11a..2023887 100644
--- a/luni/src/main/java/java/net/HttpURLConnection.java
+++ b/luni/src/main/java/java/net/HttpURLConnection.java
@@ -65,7 +65,6 @@
* }</pre>
*
* <h3>Secure Communication with HTTPS</h3>
-
* Calling {@link URL#openConnection()} on a URL with the "https"
* scheme will return an {@code HttpsURLConnection}, which allows for
* overriding the default {@link javax.net.ssl.HostnameVerifier
@@ -131,9 +130,9 @@
* for multiple request/response pairs. As a result, HTTP connections may be
* held open longer than necessary. Calls to {@link #disconnect()} may return
* the socket to a pool of connected sockets. This behavior can be disabled by
- * setting the "http.keepAlive" system property to "false" before issuing any
- * HTTP requests. The "http.maxConnections" property may be used to control how
- * many idle connections to each server will be held.
+ * setting the {@code http.keepAlive} system property to {@code false} before
+ * issuing any HTTP requests. The {@code http.maxConnections} property may be
+ * used to control how many idle connections to each server will be held.
*
* <p>By default, this implementation of {@code HttpURLConnection} requests that
* servers use gzip compression. Since {@link #getContentLength()} returns the
@@ -237,12 +236,22 @@
* until a connection is established.
*
* <h3>Response Caching</h3>
- * <p>{@code HttpURLConnection} supports a VM-wide HTTP response cache.
- * Implement {@link ResponseCache} and use {@link ResponseCache#setDefault} to
- * install a custom cache. Implementing this API is onerous: correct
- * implementations should follow all caching rules defined by <a
- * href="http://tools.ietf.org/html/rfc2616#section-13">Section 13 of RFC
- * 2616</a>.
+ * Android 4.0 (Ice Cream Sandwich) includes a response cache. See {@code
+ * android.net.http.HttpResponseCache} for instructions on enabling HTTP caching
+ * in your application.
+ *
+ * <h3>Avoiding Bugs In Earlier Releases</h3>
+ * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
+ * particular, calling {@code close()} on a readable {@code InputStream} could
+ * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
+ * connection pool</a>. Work around this by disabling connection pooling:
+ * <pre> {@code
+ * private void disableConnectionReuseIfNecessary() {
+ * // Work around pre-Froyo bugs in HTTP connection reuse.
+ * if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
+ * System.setProperty("http.keepAlive", "false");
+ * }
+ * }}</pre>
*
* <p>Each instance of {@code HttpURLConnection} may be used for one
* request/response pair. Instances of this class are not thread safe.
@@ -514,10 +523,13 @@
}
/**
- * Closes the connection to the HTTP server.
+ * Releases this connection so that its resources may be either reused or
+ * closed.
*
- * @see URLConnection#connect()
- * @see URLConnection#connected
+ * <p>Unlike other Java implementations, this will not necessarily close
+ * socket connections that can be reused. You can disable all connection
+ * reuse by setting the {@code http.keepAlive} system property to {@code
+ * false} before issuing any HTTP requests.
*/
public abstract void disconnect();
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index c12a350..bbe34c2 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -116,15 +116,9 @@
* brackets.
*
* <h4>DNS caching</h4>
- * <p>On Android, addresses are cached for 600 seconds (10 minutes) by default. Failed lookups are
- * cached for 10 seconds. The underlying C library or OS may cache for longer, but you can control
- * the Java-level caching with the usual {@code "networkaddress.cache.ttl"} and
- * {@code "networkaddress.cache.negative.ttl"} system properties. These are parsed as integer
- * numbers of seconds, where the special value 0 means "don't cache" and -1 means "cache forever".
- *
- * <p>Note also that on Android – unlike the RI – the cache is not unbounded. The
- * current implementation caches around 512 entries, removed on a least-recently-used basis.
- * (Obviously, you should not rely on these details.)
+ * <p>In Android 4.0 (Ice Cream Sandwich) and earlier, DNS caching was performed both by
+ * InetAddress and by the C library, which meant that DNS TTLs could not be honored correctly.
+ * In later releases, caching is done solely by the C library and DNS TTLs are honored.
*
* @see Inet4Address
* @see Inet6Address
@@ -416,11 +410,15 @@
addressCache.put(host, addresses);
return addresses;
} catch (GaiException gaiException) {
- // TODO: bionic currently returns EAI_NODATA, which is indistinguishable from a real
- // failure. We need to fix bionic before we can report a more useful error.
- // if (gaiException.error == EAI_SYSTEM) {
- // throw new SecurityException("Permission denied (missing INTERNET permission?)");
- // }
+ // If the failure appears to have been a lack of INTERNET permission, throw a clear
+ // SecurityException to aid in debugging this common mistake.
+ // http://code.google.com/p/android/issues/detail?id=15722
+ if (gaiException.getCause() instanceof ErrnoException) {
+ if (((ErrnoException) gaiException.getCause()).errno == EACCES) {
+ throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
+ }
+ }
+ // Otherwise, throw an UnknownHostException.
String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
addressCache.putUnknownHost(host, detailMessage);
throw gaiException.rethrowAsUnknownHostException(detailMessage);
@@ -447,13 +445,14 @@
}
/**
- * Returns a string containing a concise, human-readable description of this
- * IP address.
+ * Returns a string containing the host name (if available) and host address.
+ * For example: {@code "www.google.com/74.125.224.115"} or {@code "/127.0.0.1"}.
*
- * @return the description, as host/address.
+ * <p>IPv6 addresses may additionally include an interface name or scope id.
+ * For example: {@code "www.google.com/2001:4860:4001:803::1013%eth0"} or
+ * {@code "/2001:4860:4001:803::1013%2"}.
*/
- @Override
- public String toString() {
+ @Override public String toString() {
return (hostName == null ? "" : hostName) + "/" + getHostAddress();
}
diff --git a/luni/src/main/java/java/net/InetSocketAddress.java b/luni/src/main/java/java/net/InetSocketAddress.java
index 01b5301..49dcfc4 100644
--- a/luni/src/main/java/java/net/InetSocketAddress.java
+++ b/luni/src/main/java/java/net/InetSocketAddress.java
@@ -177,13 +177,11 @@
}
/**
- * Gets a string representation of this socket included the address and the
- * port number.
- *
- * @return the address and port number as a textual representation.
+ * Returns a string containing the address (or the hostname for an
+ * unresolved {@code InetSocketAddress}) and port number.
+ * For example: {@code "www.google.com/74.125.224.115:80"} or {@code "/127.0.0.1:80"}.
*/
- @Override
- public String toString() {
+ @Override public String toString() {
return ((addr != null) ? addr.toString() : hostname) + ":" + port;
}
diff --git a/luni/src/main/java/java/net/InterfaceAddress.java b/luni/src/main/java/java/net/InterfaceAddress.java
index 612eeb4..dea618c 100644
--- a/luni/src/main/java/java/net/InterfaceAddress.java
+++ b/luni/src/main/java/java/net/InterfaceAddress.java
@@ -96,13 +96,11 @@
}
/**
- * Returns a string representation for this interface address.
- * The string is of the form: InetAddress / prefix length [ broadcast address ].
- *
- * @return a string representation of this interface address.
+ * Returns a string containing this interface's address, prefix length, and broadcast address.
+ * For example: {@code "/172.18.103.112/23 [/172.18.103.255]"} or
+ * {@code "/0:0:0:0:0:0:0:1%1/128 [null]"}.
*/
- @Override
- public String toString() {
+ @Override public String toString() {
return address + "/" + prefixLength + " [" + broadcastAddress + "]";
}
diff --git a/luni/src/main/java/java/net/NetworkInterface.java b/luni/src/main/java/java/net/NetworkInterface.java
index c6d9af4..e06b811 100644
--- a/luni/src/main/java/java/net/NetworkInterface.java
+++ b/luni/src/main/java/java/net/NetworkInterface.java
@@ -266,34 +266,37 @@
private static List<NetworkInterface> getNetworkInterfacesList() throws SocketException {
String[] interfaceNames = new File("/sys/class/net").list();
NetworkInterface[] interfaces = new NetworkInterface[interfaceNames.length];
+ boolean[] done = new boolean[interfaces.length];
for (int i = 0; i < interfaceNames.length; ++i) {
interfaces[i] = NetworkInterface.getByName(interfaceNames[i]);
+ // http://b/5833739: getByName can return null if the interface went away between our
+ // readdir(2) and our stat(2), so mark interfaces that disappeared as 'done'.
+ if (interfaces[i] == null) {
+ done[i] = true;
+ }
}
List<NetworkInterface> result = new ArrayList<NetworkInterface>();
- boolean[] peeked = new boolean[interfaces.length];
for (int counter = 0; counter < interfaces.length; counter++) {
- // If this interface has been touched, continue.
- if (peeked[counter]) {
+ // If this interface has been dealt with already, continue.
+ if (done[counter]) {
continue;
}
int counter2 = counter;
// Checks whether the following interfaces are children.
for (; counter2 < interfaces.length; counter2++) {
- if (peeked[counter2]) {
+ if (done[counter2]) {
continue;
}
if (interfaces[counter2].name.startsWith(interfaces[counter].name + ":")) {
- // Tagged as peeked
- peeked[counter2] = true;
interfaces[counter].children.add(interfaces[counter2]);
interfaces[counter2].parent = interfaces[counter];
interfaces[counter].addresses.addAll(interfaces[counter2].addresses);
- }
+ done[counter2] = true;
+ }
}
- // Tagged as peeked
result.add(interfaces[counter]);
- peeked[counter] = true;
+ done[counter] = true;
}
return result;
}
@@ -334,6 +337,11 @@
return name.hashCode();
}
+ /**
+ * Returns a string containing details of this network interface.
+ * The exact format is deliberately unspecified. Callers that require a specific
+ * format should build a string themselves, using this class' accessor methods.
+ */
@Override public String toString() {
StringBuilder sb = new StringBuilder(25);
sb.append("[");
diff --git a/luni/src/main/java/java/net/ProxySelector.java b/luni/src/main/java/java/net/ProxySelector.java
index 1166db7..816c70f 100644
--- a/luni/src/main/java/java/net/ProxySelector.java
+++ b/luni/src/main/java/java/net/ProxySelector.java
@@ -29,11 +29,11 @@
* <tr class="TableHeadingColor"><th colspan="4">Hostname patterns</th></tr>
* <tr><th>URL scheme</th><th>property name</th><th>description</th><th>default</th></tr>
* <tr><td>ftp</td><td>ftp.nonProxyHosts</td><td>Hostname pattern for FTP servers to connect to
- * directly (without a proxy).</td><td>*</td></tr>
+ * directly (without a proxy).</td><td></td></tr>
* <tr><td>http</td><td>http.nonProxyHosts</td><td>Hostname pattern for HTTP servers to connect to
- * directly (without a proxy).</td><td>*</td></tr>
+ * directly (without a proxy).</td><td></td></tr>
* <tr><td>https</td><td>https.nonProxyHosts</td><td>Hostname pattern for HTTPS servers to connect
- * to directly (without a proxy).</td><td>*</td></tr>
+ * to directly (without a proxy).</td><td></td></tr>
* <tr><td colspan="4"><br></td></tr>
*
* <tr class="TableHeadingColor"><th colspan="4">{@linkplain Proxy.Type#HTTP HTTP Proxies}</th></tr>
diff --git a/luni/src/main/java/libcore/net/http/ResponseSource.java b/luni/src/main/java/java/net/ResponseSource.java
similarity index 89%
rename from luni/src/main/java/libcore/net/http/ResponseSource.java
rename to luni/src/main/java/java/net/ResponseSource.java
index 731e37f..fb974e9 100644
--- a/luni/src/main/java/libcore/net/http/ResponseSource.java
+++ b/luni/src/main/java/java/net/ResponseSource.java
@@ -14,9 +14,14 @@
* limitations under the License.
*/
-package libcore.net.http;
+package java.net;
-enum ResponseSource {
+/**
+ * Where the HTTP client should look for a response.
+ *
+ * @hide
+ */
+public enum ResponseSource {
/**
* Return the response from the cache immediately.
diff --git a/luni/src/main/java/java/net/URL.java b/luni/src/main/java/java/net/URL.java
index b25d223..9d44498 100644
--- a/luni/src/main/java/java/net/URL.java
+++ b/luni/src/main/java/java/net/URL.java
@@ -340,8 +340,8 @@
* devices. Two URLs could be equal on some networks and unequal on
* others.</li>
* </ul>
- * <p>This problem is fixed in Android in the Ice Cream Sandwich release. In
- * that release, URLs are only equal if their host names are equal (ignoring
+ * <p>This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that
+ * release, URLs are only equal if their host names are equal (ignoring
* case).
*/
@Override public boolean equals(Object o) {
diff --git a/luni/src/main/java/java/net/URLConnection.java b/luni/src/main/java/java/net/URLConnection.java
index a8d967c..7cf71d5 100644
--- a/luni/src/main/java/java/net/URLConnection.java
+++ b/luni/src/main/java/java/net/URLConnection.java
@@ -972,57 +972,54 @@
}
/**
- * Sets the timeout value in milliseconds for establishing the connection to
- * the resource pointed by this {@code URLConnection} instance. A {@code
- * SocketTimeoutException} is thrown if the connection could not be
- * established in this time. Default is {@code 0} which stands for an
- * infinite timeout.
+ * Sets the maximum time to wait for a connect to complete before giving up.
+ * Connecting to a server will fail with a {@link SocketTimeoutException} if
+ * the timeout elapses before a connection is established. The default value
+ * of {@code 0} disables connect timeouts; connect attempts may wait
+ * indefinitely.
*
- * @param timeout
- * the connecting timeout in milliseconds.
- * @throws IllegalArgumentException
- * if the parameter {@code timeout} is less than zero.
+ * <p><strong>Warning:</strong> if the hostname resolves to multiple IP
+ * addresses, this client will try each in <a
+ * href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order. If
+ * connecting to each of these addresses fails, multiple timeouts will
+ * elapse before the connect attempt throws an exception. Host names that
+ * support both IPv6 and IPv4 always have at least 2 IP addresses.
+ *
+ * @param timeoutMillis the connect timeout in milliseconds. Non-negative.
*/
- public void setConnectTimeout(int timeout) {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout < 0");
+ public void setConnectTimeout(int timeoutMillis) {
+ if (timeoutMillis < 0) {
+ throw new IllegalArgumentException("timeoutMillis < 0");
}
- this.connectTimeout = timeout;
+ this.connectTimeout = timeoutMillis;
}
/**
- * Returns the configured connecting timeout.
- *
- * @return the connecting timeout value in milliseconds.
+ * Returns the connect timeout in milliseconds, or {@code 0} if connect
+ * attempts never timeout.
*/
public int getConnectTimeout() {
return connectTimeout;
}
/**
- * Sets the timeout value in milliseconds for reading from the input stream
- * of an established connection to the resource. A {@code
- * SocketTimeoutException} is thrown if the connection could not be
- * established in this time. Default is {@code 0} which stands for an
- * infinite timeout.
+ * Sets the maximum time to wait for an input stream read to complete before
+ * giving up. Reading will fail with a {@link SocketTimeoutException} if the
+ * timeout elapses before data becomes available. The default value of
+ * {@code 0} disables read timeouts; read attempts will block indefinitely.
*
- * @param timeout
- * the reading timeout in milliseconds.
- * @throws IllegalArgumentException
- * if the parameter {@code timeout} is less than zero.
+ * @param timeoutMillis the read timeout in milliseconds. Non-negative.
*/
- public void setReadTimeout(int timeout) {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout < 0");
+ public void setReadTimeout(int timeoutMillis) {
+ if (timeoutMillis < 0) {
+ throw new IllegalArgumentException("timeoutMillis < 0");
}
- this.readTimeout = timeout;
+ this.readTimeout = timeoutMillis;
}
/**
- * Returns the configured timeout for reading from the input stream of an
- * established connection to the resource.
- *
- * @return the reading timeout value in milliseconds.
+ * Returns the read timeout in milliseconds, or {@code 0} if reads never
+ * timeout.
*/
public int getReadTimeout() {
return readTimeout;
diff --git a/luni/src/main/java/java/net/URLDecoder.java b/luni/src/main/java/java/net/URLDecoder.java
index e34fe4a..175175d 100644
--- a/luni/src/main/java/java/net/URLDecoder.java
+++ b/luni/src/main/java/java/net/URLDecoder.java
@@ -42,7 +42,7 @@
*/
@Deprecated
public static String decode(String s) {
- return UriCodec.decode(s, true, Charset.defaultCharset());
+ return UriCodec.decode(s, true, Charset.defaultCharset(), true);
}
/**
@@ -64,6 +64,6 @@
* if the specified encoding scheme is invalid.
*/
public static String decode(String s, String encoding) throws UnsupportedEncodingException {
- return UriCodec.decode(s, true, Charset.forName(encoding));
+ return UriCodec.decode(s, true, Charset.forName(encoding), true);
}
}
diff --git a/luni/src/main/java/java/nio/CharSequenceAdapter.java b/luni/src/main/java/java/nio/CharSequenceAdapter.java
index 3bed096..12bac31 100644
--- a/luni/src/main/java/java/nio/CharSequenceAdapter.java
+++ b/luni/src/main/java/java/nio/CharSequenceAdapter.java
@@ -102,18 +102,15 @@
return ByteOrder.nativeOrder();
}
- @Override
- protected char[] protectedArray() {
+ @Override char[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/CharToByteBufferAdapter.java b/luni/src/main/java/java/nio/CharToByteBufferAdapter.java
index a271274..b9100a2 100644
--- a/luni/src/main/java/java/nio/CharToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/CharToByteBufferAdapter.java
@@ -125,18 +125,15 @@
return byteBuffer.order();
}
- @Override
- protected char[] protectedArray() {
+ @Override char[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/DirectByteBuffer.java b/luni/src/main/java/java/nio/DirectByteBuffer.java
index ccc5c6b..0ddef14 100644
--- a/luni/src/main/java/java/nio/DirectByteBuffer.java
+++ b/luni/src/main/java/java/nio/DirectByteBuffer.java
@@ -205,7 +205,7 @@
block.free();
}
- @Override protected byte[] protectedArray() {
+ @Override byte[] protectedArray() {
byte[] array = this.block.array();
if (array == null) {
throw new UnsupportedOperationException();
@@ -213,12 +213,12 @@
return array;
}
- @Override protected int protectedArrayOffset() {
- protectedArray(); // Check we have an array.
+ @Override int protectedArrayOffset() {
+ protectedArray(); // Throw if we don't have an array.
return offset;
}
- @Override protected boolean protectedHasArray() {
- return protectedArray() != null;
+ @Override boolean protectedHasArray() {
+ return this.block.array() != null;
}
}
diff --git a/luni/src/main/java/java/nio/DoubleToByteBufferAdapter.java b/luni/src/main/java/java/nio/DoubleToByteBufferAdapter.java
index 9f7dda7..8b1e084 100644
--- a/luni/src/main/java/java/nio/DoubleToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/DoubleToByteBufferAdapter.java
@@ -125,18 +125,15 @@
return byteBuffer.order();
}
- @Override
- protected double[] protectedArray() {
+ @Override double[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/FloatToByteBufferAdapter.java b/luni/src/main/java/java/nio/FloatToByteBufferAdapter.java
index f674fe3..0ed944b 100644
--- a/luni/src/main/java/java/nio/FloatToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/FloatToByteBufferAdapter.java
@@ -124,18 +124,15 @@
return byteBuffer.order();
}
- @Override
- protected float[] protectedArray() {
+ @Override float[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/IntToByteBufferAdapter.java b/luni/src/main/java/java/nio/IntToByteBufferAdapter.java
index 1694e77..1af5f86 100644
--- a/luni/src/main/java/java/nio/IntToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/IntToByteBufferAdapter.java
@@ -125,18 +125,15 @@
return byteBuffer.order();
}
- @Override
- protected int[] protectedArray() {
+ @Override int[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/LongToByteBufferAdapter.java b/luni/src/main/java/java/nio/LongToByteBufferAdapter.java
index 5f51d96..e8bf8df 100644
--- a/luni/src/main/java/java/nio/LongToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/LongToByteBufferAdapter.java
@@ -125,18 +125,15 @@
return byteBuffer.order();
}
- @Override
- protected long[] protectedArray() {
+ @Override long[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/MappedByteBufferAdapter.java b/luni/src/main/java/java/nio/MappedByteBufferAdapter.java
index 73b2991..59cfe8e 100644
--- a/luni/src/main/java/java/nio/MappedByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/MappedByteBufferAdapter.java
@@ -360,18 +360,15 @@
return result;
}
- @Override
- byte[] protectedArray() {
+ @Override byte[] protectedArray() {
return wrapped.protectedArray();
}
- @Override
- int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return wrapped.protectedArrayOffset();
}
- @Override
- boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return wrapped.protectedHasArray();
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyCharArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyCharArrayBuffer.java
index 6f30dbc..75e7b9b 100644
--- a/luni/src/main/java/java/nio/ReadOnlyCharArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyCharArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected char[] protectedArray() {
+ @Override char[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyDoubleArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyDoubleArrayBuffer.java
index 460bbf4..9812789 100644
--- a/luni/src/main/java/java/nio/ReadOnlyDoubleArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyDoubleArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected double[] protectedArray() {
+ @Override double[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyFloatArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyFloatArrayBuffer.java
index 775e1d8..3c74966 100644
--- a/luni/src/main/java/java/nio/ReadOnlyFloatArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyFloatArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected float[] protectedArray() {
+ @Override float[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyHeapByteBuffer.java b/luni/src/main/java/java/nio/ReadOnlyHeapByteBuffer.java
index 382794e..c5073b0 100644
--- a/luni/src/main/java/java/nio/ReadOnlyHeapByteBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyHeapByteBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected byte[] protectedArray() {
+ @Override byte[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyIntArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyIntArrayBuffer.java
index a137b3b..ef73251 100644
--- a/luni/src/main/java/java/nio/ReadOnlyIntArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyIntArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected int[] protectedArray() {
+ @Override int[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyLongArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyLongArrayBuffer.java
index 87b0c88..a28815d 100644
--- a/luni/src/main/java/java/nio/ReadOnlyLongArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyLongArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected long[] protectedArray() {
+ @Override long[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadOnlyShortArrayBuffer.java b/luni/src/main/java/java/nio/ReadOnlyShortArrayBuffer.java
index 07b9c90..075ff38 100644
--- a/luni/src/main/java/java/nio/ReadOnlyShortArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadOnlyShortArrayBuffer.java
@@ -64,18 +64,15 @@
return true;
}
- @Override
- protected short[] protectedArray() {
+ @Override short[] protectedArray() {
throw new ReadOnlyBufferException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new ReadOnlyBufferException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteCharArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteCharArrayBuffer.java
index df125b3..58fc5ae 100644
--- a/luni/src/main/java/java/nio/ReadWriteCharArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteCharArrayBuffer.java
@@ -75,18 +75,15 @@
return false;
}
- @Override
- protected char[] protectedArray() {
+ @Override char[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteDoubleArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteDoubleArrayBuffer.java
index a2913ae..f9328d6 100644
--- a/luni/src/main/java/java/nio/ReadWriteDoubleArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteDoubleArrayBuffer.java
@@ -76,18 +76,15 @@
return false;
}
- @Override
- protected double[] protectedArray() {
+ @Override double[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteFloatArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteFloatArrayBuffer.java
index da1e406..eee3aa7 100644
--- a/luni/src/main/java/java/nio/ReadWriteFloatArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteFloatArrayBuffer.java
@@ -76,18 +76,15 @@
return false;
}
- @Override
- protected float[] protectedArray() {
+ @Override float[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteHeapByteBuffer.java b/luni/src/main/java/java/nio/ReadWriteHeapByteBuffer.java
index 5358a13..02296c6 100644
--- a/luni/src/main/java/java/nio/ReadWriteHeapByteBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteHeapByteBuffer.java
@@ -77,18 +77,15 @@
return false;
}
- @Override
- protected byte[] protectedArray() {
+ @Override byte[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteIntArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteIntArrayBuffer.java
index 8ec60c0..e8e67c2 100644
--- a/luni/src/main/java/java/nio/ReadWriteIntArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteIntArrayBuffer.java
@@ -75,18 +75,15 @@
return false;
}
- @Override
- protected int[] protectedArray() {
+ @Override int[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteLongArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteLongArrayBuffer.java
index d02ec57..df5f09f 100644
--- a/luni/src/main/java/java/nio/ReadWriteLongArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteLongArrayBuffer.java
@@ -75,18 +75,15 @@
return false;
}
- @Override
- protected long[] protectedArray() {
+ @Override long[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/ReadWriteShortArrayBuffer.java b/luni/src/main/java/java/nio/ReadWriteShortArrayBuffer.java
index 6f16dae..2a43e91 100644
--- a/luni/src/main/java/java/nio/ReadWriteShortArrayBuffer.java
+++ b/luni/src/main/java/java/nio/ReadWriteShortArrayBuffer.java
@@ -77,18 +77,15 @@
return false;
}
- @Override
- protected short[] protectedArray() {
+ @Override short[] protectedArray() {
return backingArray;
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
return offset;
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return true;
}
diff --git a/luni/src/main/java/java/nio/SelectorImpl.java b/luni/src/main/java/java/nio/SelectorImpl.java
index 786e05f..05a6497 100644
--- a/luni/src/main/java/java/nio/SelectorImpl.java
+++ b/luni/src/main/java/java/nio/SelectorImpl.java
@@ -170,7 +170,7 @@
synchronized (keysLock) {
preparePollFds();
}
- int rc;
+ int rc = -1;
try {
if (isBlock) {
begin();
@@ -178,7 +178,9 @@
try {
rc = Libcore.os.poll(pollFds.array(), (int) timeout);
} catch (ErrnoException errnoException) {
- throw errnoException.rethrowAsIOException();
+ if (errnoException.errno != EINTR) {
+ throw errnoException.rethrowAsIOException();
+ }
}
} finally {
if (isBlock) {
diff --git a/luni/src/main/java/java/nio/ShortToByteBufferAdapter.java b/luni/src/main/java/java/nio/ShortToByteBufferAdapter.java
index 3fa2a63..ee36709 100644
--- a/luni/src/main/java/java/nio/ShortToByteBufferAdapter.java
+++ b/luni/src/main/java/java/nio/ShortToByteBufferAdapter.java
@@ -124,18 +124,15 @@
return byteBuffer.order();
}
- @Override
- protected short[] protectedArray() {
+ @Override short[] protectedArray() {
throw new UnsupportedOperationException();
}
- @Override
- protected int protectedArrayOffset() {
+ @Override int protectedArrayOffset() {
throw new UnsupportedOperationException();
}
- @Override
- protected boolean protectedHasArray() {
+ @Override boolean protectedHasArray() {
return false;
}
diff --git a/luni/src/main/java/java/util/AbstractList.java b/luni/src/main/java/java/util/AbstractList.java
index 3b522c0..d35e543 100644
--- a/luni/src/main/java/java/util/AbstractList.java
+++ b/luni/src/main/java/java/util/AbstractList.java
@@ -398,7 +398,7 @@
* @throws IllegalArgumentException
* if the object cannot be added to this List
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location > size()}
*/
public void add(int location, E object) {
throw new UnsupportedOperationException();
@@ -443,7 +443,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this list.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || > size()}
+ * if {@code location < 0 || location > size()}
*/
public boolean addAll(int location, Collection<? extends E> collection) {
Iterator<? extends E> it = collection.iterator();
@@ -507,7 +507,7 @@
* the index of the element to return.
* @return the element at the specified index.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public abstract E get(int location);
@@ -632,7 +632,7 @@
* @throws UnsupportedOperationException
* if removing from this list is not supported.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public E remove(int location) {
throw new UnsupportedOperationException();
@@ -675,7 +675,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this list.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public E set(int location, E object) {
throw new UnsupportedOperationException();
diff --git a/luni/src/main/java/java/util/ArrayList.java b/luni/src/main/java/java/util/ArrayList.java
index 3797e15..dc7b198 100644
--- a/luni/src/main/java/java/util/ArrayList.java
+++ b/luni/src/main/java/java/util/ArrayList.java
@@ -134,7 +134,7 @@
* @param object
* the object to add.
* @throws IndexOutOfBoundsException
- * when {@code location < 0 || > size()}
+ * when {@code location < 0 || location > size()}
*/
@Override public void add(int index, E object) {
Object[] a = array;
@@ -213,7 +213,7 @@
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
* @throws IndexOutOfBoundsException
- * when {@code location < 0 || > size()}
+ * when {@code location < 0 || location > size()}
*/
@Override
public boolean addAll(int index, Collection<? extends E> collection) {
@@ -390,7 +390,7 @@
* the index of the object to remove.
* @return the removed object.
* @throws IndexOutOfBoundsException
- * when {@code location < 0 || >= size()}
+ * when {@code location < 0 || location >= size()}
*/
@Override public E remove(int index) {
Object[] a = array;
@@ -469,7 +469,7 @@
* the object to add.
* @return the previous element at the index.
* @throws IndexOutOfBoundsException
- * when {@code location < 0 || >= size()}
+ * when {@code location < 0 || location >= size()}
*/
@Override public E set(int index, E object) {
Object[] a = array;
diff --git a/luni/src/main/java/java/util/BitSet.java b/luni/src/main/java/java/util/BitSet.java
index a841315..a4ee4c1 100644
--- a/luni/src/main/java/java/util/BitSet.java
+++ b/luni/src/main/java/java/util/BitSet.java
@@ -602,7 +602,7 @@
while (++arrayIndex < longCount && bits[arrayIndex] == ALL_ONES) {
}
if (arrayIndex == longCount) {
- return size();
+ return 64 * longCount;
}
return 64 * arrayIndex + Long.numberOfTrailingZeros(~bits[arrayIndex]);
}
diff --git a/luni/src/main/java/java/util/Currency.java b/luni/src/main/java/java/util/Currency.java
index 3b80e99..ceda24e 100644
--- a/luni/src/main/java/java/util/Currency.java
+++ b/luni/src/main/java/java/util/Currency.java
@@ -79,7 +79,7 @@
String currencyCode = ICU.getCurrencyCode(country);
if (currencyCode == null) {
throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
- } else if (currencyCode.equals("None")) {
+ } else if (currencyCode.equals("XXX")) {
return null;
}
Currency result = getInstance(currencyCode);
diff --git a/luni/src/main/java/java/util/LinkedList.java b/luni/src/main/java/java/util/LinkedList.java
index a1dc8d8..325b16d 100644
--- a/luni/src/main/java/java/util/LinkedList.java
+++ b/luni/src/main/java/java/util/LinkedList.java
@@ -272,7 +272,7 @@
* @param object
* the object to add.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location > size()}
*/
@Override
public void add(int location, E object) {
@@ -336,7 +336,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this list.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || > size()}
+ * if {@code location < 0 || location > size()}
*/
@Override
public boolean addAll(int location, Collection<? extends E> collection) {
@@ -619,7 +619,7 @@
* the index at which to start the iteration
* @return a ListIterator on the elements of this {@code LinkedList}
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location > size()}
* @see ListIterator
*/
@Override
@@ -634,7 +634,7 @@
* the index of the object to remove
* @return the removed object
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
@Override
public E remove(int location) {
@@ -855,7 +855,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this list.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
@Override
public E set(int location, E object) {
diff --git a/luni/src/main/java/java/util/List.java b/luni/src/main/java/java/util/List.java
index c27ca3f..8a9e1e3 100644
--- a/luni/src/main/java/java/util/List.java
+++ b/luni/src/main/java/java/util/List.java
@@ -84,7 +84,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this {@code List}.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || > size()}
+ * if {@code location < 0 || location > size()}
*/
public boolean addAll(int location, Collection<? extends E> collection);
@@ -159,7 +159,7 @@
* the index of the element to return.
* @return the element at the specified location.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public E get(int location);
@@ -244,7 +244,7 @@
* @throws UnsupportedOperationException
* if removing from this {@code List} is not supported.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public E remove(int location);
@@ -301,7 +301,7 @@
* @throws IllegalArgumentException
* if an object cannot be added to this {@code List}.
* @throws IndexOutOfBoundsException
- * if {@code location < 0 || >= size()}
+ * if {@code location < 0 || location >= size()}
*/
public E set(int location, E object);
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index 74126cc..6b20a1c 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -69,7 +69,8 @@
* <tr><td>cupcake/donut/eclair</td> <td>ICU 3.8</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
* <tr><td>froyo</td> <td>ICU 4.2</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
* <tr><td>gingerbread/honeycomb</td><td>ICU 4.4</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
- * <tr><td>ice cream sandwich</td><td>ICU 4.6</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td> <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>ice cream sandwich</td> <td>ICU 4.6</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td> <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>jelly bean</td> <td>ICU 4.8</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td> <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
* </table>
*
* <a name="default_locale"><h3>Be wary of the default locale</h3></a>
diff --git a/luni/src/main/java/java/util/TimeZone.java b/luni/src/main/java/java/util/TimeZone.java
index e7253f7..969e164 100644
--- a/luni/src/main/java/java/util/TimeZone.java
+++ b/luni/src/main/java/java/util/TimeZone.java
@@ -269,7 +269,8 @@
public abstract int getRawOffset();
/**
- * Returns a {@code TimeZone} corresponding to the given {@code id}, or {@code GMT} on failure.
+ * Returns a {@code TimeZone} corresponding to the given {@code id}, or {@code GMT}
+ * for unknown ids.
*
* <p>An ID can be an Olson name of the form <i>Area</i>/<i>Location</i>, such
* as {@code America/Los_Angeles}. The {@link #getAvailableIDs} method returns
@@ -287,6 +288,9 @@
* zone IDs used in Java 1.1.
*/
public static synchronized TimeZone getTimeZone(String id) {
+ if (id == null) {
+ throw new NullPointerException("id == null");
+ }
TimeZone zone = ZoneInfoDB.getTimeZone(id);
if (zone != null) {
return zone;
diff --git a/luni/src/main/java/java/util/TreeMap.java b/luni/src/main/java/java/util/TreeMap.java
index 7809110..9e19933 100644
--- a/luni/src/main/java/java/util/TreeMap.java
+++ b/luni/src/main/java/java/util/TreeMap.java
@@ -132,7 +132,7 @@
*
* <p>The constructed map <strong>will always use</strong> {@code
* copyFrom}'s ordering. Because the {@code TreeMap} constructor overloads
- * are ambigous, prefer to construct a map and populate it in two steps:
+ * are ambiguous, prefer to construct a map and populate it in two steps:
* <pre> {@code
* TreeMap<String, Integer> customOrderedMap
* = new TreeMap<String, Integer>(copyFrom.comparator());
@@ -1364,11 +1364,12 @@
}
public Comparator<? super K> comparator() {
- if (ascending) {
- return TreeMap.this.comparator();
- } else {
- return Collections.reverseOrder(comparator);
- }
+ Comparator<? super K> forward = TreeMap.this.comparator();
+ if (ascending) {
+ return forward;
+ } else {
+ return Collections.reverseOrder(forward);
+ }
}
/*
@@ -1665,7 +1666,7 @@
private static final long serialVersionUID = 919286545866124006L;
private void writeObject(ObjectOutputStream stream) throws IOException {
- stream.putFields().put("comparator", comparator != NATURAL_ORDER ? comparator : null);
+ stream.putFields().put("comparator", comparator());
stream.writeFields();
stream.writeInt(size);
for (Map.Entry<K, V> entry : entrySet()) {
diff --git a/luni/src/main/java/java/util/zip/ZipFile.java b/luni/src/main/java/java/util/zip/ZipFile.java
index e576d85..363f57e 100644
--- a/luni/src/main/java/java/util/zip/ZipFile.java
+++ b/luni/src/main/java/java/util/zip/ZipFile.java
@@ -318,7 +318,7 @@
*/
long scanOffset = mRaf.length() - ENDHDR;
if (scanOffset < 0) {
- throw new ZipException("too short to be Zip");
+ throw new ZipException("File too short to be a zip file: " + mRaf.length());
}
long stopOffset = scanOffset - 65536;
@@ -346,10 +346,10 @@
// Pull out the information we need.
BufferIterator it = HeapBufferIterator.iterator(eocd, 0, eocd.length, ByteOrder.LITTLE_ENDIAN);
- short diskNumber = it.readShort();
- short diskWithCentralDir = it.readShort();
- short numEntries = it.readShort();
- short totalNumEntries = it.readShort();
+ int diskNumber = it.readShort() & 0xffff;
+ int diskWithCentralDir = it.readShort() & 0xffff;
+ int numEntries = it.readShort() & 0xffff;
+ int totalNumEntries = it.readShort() & 0xffff;
it.skip(4); // Ignore centralDirSize.
int centralDirOffset = it.readInt();
diff --git a/luni/src/main/java/java/util/zip/ZipInputStream.java b/luni/src/main/java/java/util/zip/ZipInputStream.java
index c9f25c0..d082fc7 100644
--- a/luni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipInputStream.java
@@ -227,6 +227,7 @@
return null;
}
+ // Read the signature to see whether there's another local file header.
Streams.readFully(in, hdrBuf, 0, 4);
int hdr = Memory.peekInt(hdrBuf, 0, ByteOrder.LITTLE_ENDIAN);
if (hdr == CENSIG) {
@@ -237,28 +238,28 @@
return null;
}
- // Read the local header
+ // Read the local file header.
Streams.readFully(in, hdrBuf, 0, (LOCHDR - LOCVER));
- int version = Memory.peekShort(hdrBuf, 0, ByteOrder.LITTLE_ENDIAN) & 0xff;
+ int version = peekShort(0) & 0xff;
if (version > ZIPLocalHeaderVersionNeeded) {
throw new ZipException("Cannot read local header version " + version);
}
- short flags = Memory.peekShort(hdrBuf, LOCFLG - LOCVER, ByteOrder.LITTLE_ENDIAN);
+ int flags = peekShort(LOCFLG - LOCVER);
hasDD = ((flags & ZipFile.GPBF_DATA_DESCRIPTOR_FLAG) != 0);
- int ceTime = Memory.peekShort(hdrBuf, LOCTIM - LOCVER, ByteOrder.LITTLE_ENDIAN) & 0xffff;
- int ceModDate = Memory.peekShort(hdrBuf, LOCTIM - LOCVER + 2, ByteOrder.LITTLE_ENDIAN) & 0xffff;
- int ceCompressionMethod = Memory.peekShort(hdrBuf, LOCHOW - LOCVER, ByteOrder.LITTLE_ENDIAN) & 0xffff;
+ int ceLastModifiedTime = peekShort(LOCTIM - LOCVER);
+ int ceLastModifiedDate = peekShort(LOCTIM - LOCVER + 2);
+ int ceCompressionMethod = peekShort(LOCHOW - LOCVER);
long ceCrc = 0, ceCompressedSize = 0, ceSize = -1;
if (!hasDD) {
ceCrc = ((long) Memory.peekInt(hdrBuf, LOCCRC - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
ceCompressedSize = ((long) Memory.peekInt(hdrBuf, LOCSIZ - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
ceSize = ((long) Memory.peekInt(hdrBuf, LOCLEN - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL;
}
- int nameLength = Memory.peekShort(hdrBuf, LOCNAM - LOCVER, ByteOrder.LITTLE_ENDIAN) & 0xffff;
+ int nameLength = peekShort(LOCNAM - LOCVER);
if (nameLength == 0) {
throw new ZipException("Entry is not named");
}
- int extraLength = Memory.peekShort(hdrBuf, LOCEXT - LOCVER, ByteOrder.LITTLE_ENDIAN) & 0xffff;
+ int extraLength = peekShort(LOCEXT - LOCVER);
if (nameLength > nameBuf.length) {
nameBuf = new byte[nameLength];
@@ -268,8 +269,8 @@
}
Streams.readFully(in, nameBuf, 0, nameLength);
currentEntry = createZipEntry(ModifiedUtf8.decode(nameBuf, charBuf, 0, nameLength));
- currentEntry.time = ceTime;
- currentEntry.modDate = ceModDate;
+ currentEntry.time = ceLastModifiedTime;
+ currentEntry.modDate = ceLastModifiedDate;
currentEntry.setMethod(ceCompressionMethod);
if (ceSize != -1) {
currentEntry.setCrc(ceCrc);
@@ -284,6 +285,10 @@
return currentEntry;
}
+ private int peekShort(int offset) {
+ return Memory.peekShort(hdrBuf, offset, ByteOrder.LITTLE_ENDIAN) & 0xffff;
+ }
+
/**
* Reads up to the specified number of uncompressed bytes into the buffer
* starting at the offset.
diff --git a/luni/src/main/java/java/util/zip/ZipOutputStream.java b/luni/src/main/java/java/util/zip/ZipOutputStream.java
index 624847a..9a56fa2 100644
--- a/luni/src/main/java/java/util/zip/ZipOutputStream.java
+++ b/luni/src/main/java/java/util/zip/ZipOutputStream.java
@@ -21,8 +21,8 @@
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charsets;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
/**
* This class provides an implementation of {@code FilterOutputStream} that
@@ -78,7 +78,7 @@
private String comment;
- private final ArrayList<String> entries = new ArrayList<String>();
+ private final HashSet<String> entries = new HashSet<String>();
private int compressMethod = DEFLATED;
@@ -284,6 +284,10 @@
if (entries.contains(ze.name)) {
throw new ZipException("Entry already exists: " + ze.name);
}
+ if (entries.size() == 64*1024-1) {
+ // TODO: support Zip64.
+ throw new ZipException("Too many entries for the zip file format's 16-bit entry count");
+ }
nameBytes = ze.name.getBytes(Charsets.UTF_8);
nameLength = nameBytes.length;
if (nameLength > 0xffff) {
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index c8cb601..1dacd46 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -886,17 +886,25 @@
if (input == null) {
throw new IllegalArgumentException("input == null");
}
- if (inputOffset < 0 || inputLen < 0
- || inputLen > input.length
- || inputOffset > input.length - inputLen) {
- throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
- }
+ checkInputOffsetAndCount(input.length, inputOffset, inputLen);
if (input.length == 0) {
return null;
}
return spiImpl.engineUpdate(input, inputOffset, inputLen);
}
+ private static void checkInputOffsetAndCount(int inputArrayLength,
+ int inputOffset,
+ int inputLen) {
+ if ((inputOffset | inputLen) < 0
+ || inputOffset > inputArrayLength
+ || inputArrayLength - inputOffset < inputLen) {
+ throw new IllegalArgumentException("input.length=" + inputArrayLength
+ + "; inputOffset=" + inputOffset
+ + "; inputLen=" + inputLen);
+ }
+ }
+
/**
* Continues a multi-part transformation (encryption or decryption). The
* transformed bytes are stored in the {@code output} buffer.
@@ -972,12 +980,9 @@
throw new IllegalArgumentException("output == null");
}
if (outputOffset < 0) {
- throw new IllegalArgumentException("outputOffset < 0");
+ throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
}
- if (inputOffset < 0 || inputLen < 0 || inputLen > input.length
- || inputOffset > input.length - inputLen) {
- throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
- }
+ checkInputOffsetAndCount(input.length, inputOffset, inputLen);
if (input.length == 0) {
return 0;
}
@@ -1075,7 +1080,7 @@
throw new IllegalStateException();
}
if (outputOffset < 0) {
- throw new IllegalArgumentException("outputOffset < 0");
+ throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset);
}
return spiImpl.engineDoFinal(null, 0, 0, output, outputOffset);
}
@@ -1137,9 +1142,7 @@
if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
throw new IllegalStateException();
}
- if (inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) {
- throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
- }
+ checkInputOffsetAndCount(input.length, inputOffset, inputLen);
return spiImpl.engineDoFinal(input, inputOffset, inputLen);
}
@@ -1217,9 +1220,7 @@
if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) {
throw new IllegalStateException();
}
- if (inputOffset < 0 || inputLen < 0 || inputOffset + inputLen > input.length) {
- throw new IllegalArgumentException("Incorrect inputOffset/inputLen parameters");
- }
+ checkInputOffsetAndCount(input.length, inputOffset, inputLen);
return spiImpl.engineDoFinal(input, inputOffset, inputLen, output,
outputOffset);
}
diff --git a/luni/src/main/java/javax/crypto/CipherInputStream.java b/luni/src/main/java/javax/crypto/CipherInputStream.java
index 4de37db..39dcfda 100644
--- a/luni/src/main/java/javax/crypto/CipherInputStream.java
+++ b/luni/src/main/java/javax/crypto/CipherInputStream.java
@@ -39,8 +39,9 @@
private final Cipher cipher;
private final byte[] inputBuffer = new byte[I_BUFFER_SIZE];
- private int index; // index of the bytes to return from outputBuffer
private byte[] outputBuffer;
+ private int outputIndex; // index of the first byte to return from outputBuffer
+ private int outputLength; // count of the bytes to return from outputBuffer
private boolean finished;
/**
@@ -84,27 +85,35 @@
@Override
public int read() throws IOException {
if (finished) {
- return ((outputBuffer == null) || (index == outputBuffer.length))
- ? -1
- : outputBuffer[index++] & 0xFF;
+ return (outputIndex == outputLength) ? -1 : outputBuffer[outputIndex++] & 0xFF;
}
- if ((outputBuffer != null) && (index < outputBuffer.length)) {
- return outputBuffer[index++] & 0xFF;
+ if (outputIndex < outputLength) {
+ return outputBuffer[outputIndex++] & 0xFF;
}
- index = 0;
- outputBuffer = null;
- int byteCount;
- while (outputBuffer == null) {
- if ((byteCount = in.read(inputBuffer)) == -1) {
+ outputIndex = 0;
+ outputLength = 0;
+ while (outputLength == 0) {
+ // check output size on each iteration since pending state
+ // in the cipher can cause this to vary from call to call
+ int outputSize = cipher.getOutputSize(inputBuffer.length);
+ if ((outputBuffer == null) || (outputBuffer.length < outputSize)) {
+ this.outputBuffer = new byte[outputSize];
+ }
+ int byteCount = in.read(inputBuffer);
+ if (byteCount == -1) {
try {
- outputBuffer = cipher.doFinal();
+ outputLength = cipher.doFinal(outputBuffer, 0);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
finished = true;
break;
}
- outputBuffer = cipher.update(inputBuffer, 0, byteCount);
+ try {
+ outputLength = cipher.update(inputBuffer, 0, byteCount, outputBuffer, 0);
+ } catch (ShortBufferException e) {
+ throw new AssertionError(e); // should not happen since we sized with getOutputSize
+ }
}
return read();
}
@@ -113,10 +122,10 @@
* Reads the next {@code len} bytes from this input stream into buffer
* {@code buf} starting at offset {@code off}.
* <p>
- * if {@code b} is {@code null}, the next {@code len} bytes are read and
+ * if {@code buf} is {@code null}, the next {@code len} bytes are read and
* discarded.
*
- * @return the number of bytes filled into buffer {@code b}, or {@code -1}
+ * @return the number of bytes filled into buffer {@code buf}, or {@code -1}
* of the of the stream is reached.
* @throws IOException
* if an error occurs.
diff --git a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
index 2fed280..e68baca 100644
--- a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
+++ b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
@@ -22,180 +22,147 @@
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import javax.security.auth.x500.X500Principal;
/**
- * A HostnameVerifier that works the same way as Curl and Firefox.
+ * A HostnameVerifier consistent with <a
+ * href="http://www.ietf.org/rfc/rfc2818.txt">RFC 2818</a>.
*
- * <p>The hostname must match either the first CN, or any of the subject-alts.
- * A wildcard can occur in the CN, and in any of the subject-alts.
- *
- * @author Julius Davies
+ * @hide accessible via HttpsURLConnection.getDefaultHostnameVerifier()
*/
-class DefaultHostnameVerifier implements HostnameVerifier {
-
- /**
- * This contains a list of 2nd-level domains that aren't allowed to
- * have wildcards when combined with country-codes.
- * For example: [*.co.uk].
- *
- * <p>The [*.co.uk] problem is an interesting one. Should we just hope
- * that CA's would never foolishly allow such a certificate to happen?
- * Looks like we're the only implementation guarding against this.
- * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
- */
- private static final String[] BAD_COUNTRY_2LDS =
- { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
- "lg", "ne", "net", "or", "org" };
-
- static {
- // Just in case developer forgot to manually sort the array. :-)
- Arrays.sort(BAD_COUNTRY_2LDS);
- }
+public final class DefaultHostnameVerifier implements HostnameVerifier {
+ private static final int ALT_DNS_NAME = 2;
+ private static final int ALT_IPA_NAME = 7;
public final boolean verify(String host, SSLSession session) {
- Certificate[] certs;
try {
- certs = session.getPeerCertificates();
+ Certificate[] certificates = session.getPeerCertificates();
+ return verify(host, (X509Certificate) certificates[0]);
} catch (SSLException e) {
return false;
}
+ }
- X509Certificate x509 = (X509Certificate) certs[0];
+ public boolean verify(String host, X509Certificate certificate) {
+ return InetAddress.isNumeric(host)
+ ? verifyIpAddress(host, certificate)
+ : verifyHostName(host, certificate);
+ }
- // We can be case-insensitive when comparing the host we used to
- // establish the socket to the hostname in the certificate.
- String hostName = host.trim().toLowerCase(Locale.ENGLISH);
+ /**
+ * Returns true if {@code certificate} matches {@code ipAddress}.
+ */
+ private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
+ for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) {
+ if (ipAddress.equalsIgnoreCase(altName)) {
+ return true;
+ }
+ }
+ return false;
+ }
- // Verify the first CN provided. Other CNs are ignored. Firefox, wget,
- // curl, and Sun Java work this way.
- String firstCn = getFirstCn(x509);
- if (matches(hostName, firstCn)) {
- return true;
+ /**
+ * Returns true if {@code certificate} matches {@code hostName}.
+ */
+ private boolean verifyHostName(String hostName, X509Certificate certificate) {
+ hostName = hostName.toLowerCase(Locale.US);
+ boolean hasDns = false;
+ for (String altName : getSubjectAltNames(certificate, ALT_DNS_NAME)) {
+ hasDns = true;
+ if (verifyHostName(hostName, altName)) {
+ return true;
+ }
}
- for (String cn : getDNSSubjectAlts(x509)) {
- if (matches(hostName, cn)) {
- return true;
+ if (!hasDns) {
+ X500Principal principal = certificate.getSubjectX500Principal();
+ String cn = new DistinguishedNameParser(principal).find("cn");
+ if (cn != null) {
+ return verifyHostName(hostName, cn);
}
}
return false;
}
+ private List<String> getSubjectAltNames(X509Certificate certificate, int type) {
+ List<String> result = new ArrayList<String>();
+ try {
+ Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
+ if (subjectAltNames == null) {
+ return Collections.emptyList();
+ }
+ for (Object subjectAltName : subjectAltNames) {
+ List<?> entry = (List<?>) subjectAltName;
+ if (entry == null || entry.size() < 2) {
+ continue;
+ }
+ Integer altNameType = (Integer) entry.get(0);
+ if (altNameType == null) {
+ continue;
+ }
+ if (altNameType == type) {
+ String altName = (String) entry.get(1);
+ if (altName != null) {
+ result.add(altName);
+ }
+ }
+ }
+ return result;
+ } catch (CertificateParsingException e) {
+ return Collections.emptyList();
+ }
+ }
+
/**
- * Returns true if {@code hostname} matches {@code cn}.
+ * Returns true if {@code hostName} matches the name or pattern {@code cn}.
*
- * @param hostName a trimmed, lowercase hostname to verify
- * @param cn a certificate CN or DNS subject alt. Either a literal name or
- * a wildcard of the form "*.google.com".
+ * @param hostName lowercase host name.
+ * @param cn certificate host name. May include wildcards like
+ * {@code *.android.com}.
*/
- private boolean matches(String hostName, String cn) {
- if (cn == null) {
+ public boolean verifyHostName(String hostName, String cn) {
+ if (hostName == null || hostName.isEmpty() || cn == null || cn.isEmpty()) {
return false;
}
- // Don't trim the CN, though!
- cn = cn.toLowerCase(Locale.ENGLISH);
+ cn = cn.toLowerCase(Locale.US);
- if (cn.startsWith("*.")) {
- // When a wildcard matches, also check that the wildcard is legit
- // - Wildcards must contain at least two dots: "*.google.com"
- // - Wildcards must be for private domains. No "*.co.uk" etc.
- // - Wildcards must not match IP addresses: "*.8.8"
- int matchLength = cn.length() - 1;
- return hostName.regionMatches(hostName.length() - matchLength, cn, 1, matchLength)
- && cn.indexOf('.', 2) != -1
- && acceptableCountryWildcard(cn)
- && !InetAddress.isNumeric(hostName);
- } else {
+ if (!cn.contains("*")) {
return hostName.equals(cn);
}
- }
- private boolean acceptableCountryWildcard(String cn) {
- int cnLen = cn.length();
- if (cnLen >= 7 && cnLen <= 9) {
- // Look for the '.' in the 3rd-last position:
- if (cn.charAt(cnLen - 3) == '.') {
- // Trim off the [*.] and the [.XX].
- String s = cn.substring(2, cnLen - 3);
- // And test against the sorted array of bad 2lds:
- int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
- return x < 0;
+ if (cn.startsWith("*.") && hostName.regionMatches(0, cn, 2, cn.length() - 2)) {
+ return true; // "*.foo.com" matches "foo.com"
+ }
+
+ int asterisk = cn.indexOf('*');
+ int dot = cn.indexOf('.');
+ if (asterisk > dot) {
+ return false; // malformed; wildcard must be in the first part of the cn
+ }
+
+ if (!hostName.regionMatches(0, cn, 0, asterisk)) {
+ return false; // prefix before '*' doesn't match
+ }
+
+ int suffixLength = cn.length() - (asterisk + 1);
+ int suffixStart = hostName.length() - suffixLength;
+ if (hostName.indexOf('.', asterisk) < suffixStart) {
+ // TODO: remove workaround for *.clients.google.com http://b/5426333
+ if (!hostName.endsWith(".clients.google.com")) {
+ return false; // wildcard '*' can't match a '.'
}
}
+
+ if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) {
+ return false; // suffix after '*' doesn't match
+ }
+
return true;
}
-
- private String getFirstCn(X509Certificate cert) {
- /*
- * Sebastian Hauer's original StrictSSLProtocolSocketFactory used
- * getName() and had the following comment:
- *
- * Parses a X.500 distinguished name for the value of the
- * "Common Name" field. This is done a bit sloppy right
- * now and should probably be done a bit more according to
- * <code>RFC 2253</code>.
- *
- * I've noticed that toString() seems to do a better job than
- * getName() on these X500Principal objects, so I'm hoping that
- * addresses Sebastian's concern.
- *
- * For example, getName() gives me this:
- * 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
- *
- * whereas toString() gives me this:
- * EMAILADDRESS=juliusdavies@cucbc.com
- *
- * Looks like toString() even works with non-ascii domain names!
- * I tested it with "花子.co.jp" and it worked fine.
- */
- String subjectPrincipal = cert.getSubjectX500Principal().toString();
- for (String token : subjectPrincipal.split(",")) {
- int x = token.indexOf("CN=");
- if (x >= 0) {
- return token.substring(x + 3);
- }
- }
- return null;
- }
-
- /**
- * Returns all SubjectAlt DNS names from an X509Certificate.
- *
- * <p>Note: Java doesn't appear able to extract international characters
- * from the SubjectAlts. It can only extract international characters
- * from the CN field.
- *
- * <p>(Or maybe the version of OpenSSL I'm using to test isn't storing the
- * international characters correctly in the SubjectAlts?).
- */
- private List<String> getDNSSubjectAlts(X509Certificate cert) {
- Collection<List<?>> subjectAlternativeNames;
- try {
- subjectAlternativeNames = cert.getSubjectAlternativeNames();
- } catch (CertificateParsingException cpe) {
- System.logI("Error parsing certificate", cpe);
- return Collections.emptyList();
- }
-
- if (subjectAlternativeNames == null) {
- return Collections.emptyList();
- }
-
- List<String> subjectAltList = new ArrayList<String>();
- for (List<?> pair : subjectAlternativeNames) {
- int type = (Integer) pair.get(0);
- // If type is 2, then we've got a dNSName
- if (type == 2) {
- subjectAltList.add((String) pair.get(1));
- }
- }
- return subjectAltList;
- }
}
diff --git a/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java b/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java
new file mode 100644
index 0000000..fa8ed1b
--- /dev/null
+++ b/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 javax.net.ssl;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A distinguished name (DN) parser. This parser only supports extracting a
+ * string value from a DN. It doesn't support values in the hex-string style.
+ *
+ * @hide
+ */
+public final class DistinguishedNameParser {
+ private final String dn;
+ private final int length;
+ private int pos;
+ private int beg;
+ private int end;
+
+ /** tmp vars to store positions of the currently parsed item */
+ private int cur;
+
+ /** distinguished name chars */
+ private char[] chars;
+
+ public DistinguishedNameParser(X500Principal principal) {
+ this.dn = principal.getName(X500Principal.RFC2253);
+ this.length = this.dn.length();
+ }
+
+ // gets next attribute type: (ALPHA 1*keychar) / oid
+ private String nextAT() {
+ // skip preceding space chars, they can present after
+ // comma or semicolon (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+ if (pos == length) {
+ return null; // reached the end of DN
+ }
+
+ // mark the beginning of attribute type
+ beg = pos;
+
+ // attribute type chars
+ pos++;
+ for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
+ // we don't follow exact BNF syntax here:
+ // accept any char except space and '='
+ }
+ if (pos >= length) {
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+
+ // mark the end of attribute type
+ end = pos;
+
+ // skip trailing space chars between attribute type and '='
+ // (compatibility with RFC 1779)
+ if (chars[pos] == ' ') {
+ for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
+ }
+
+ if (chars[pos] != '=' || pos == length) {
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+ }
+
+ pos++; //skip '=' char
+
+ // skip space chars between '=' and attribute value
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+
+ // in case of oid attribute type skip its prefix: "oid." or "OID."
+ // (compatibility with RFC 1779)
+ if ((end - beg > 4) && (chars[beg + 3] == '.')
+ && (chars[beg] == 'O' || chars[beg] == 'o')
+ && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
+ && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
+ beg += 4;
+ }
+
+ return new String(chars, beg, end - beg);
+ }
+
+ // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
+ private String quotedAV() {
+ pos++;
+ beg = pos;
+ end = beg;
+ while (true) {
+
+ if (pos == length) {
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+
+ if (chars[pos] == '"') {
+ // enclosing quotation was found
+ pos++;
+ break;
+ } else if (chars[pos] == '\\') {
+ chars[end] = getEscaped();
+ } else {
+ // shift char: required for string with escaped chars
+ chars[end] = chars[pos];
+ }
+ pos++;
+ end++;
+ }
+
+ // skip trailing space chars before comma or semicolon.
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+
+ return new String(chars, beg, end - beg);
+ }
+
+ // gets hex string attribute value: "#" hexstring
+ private String hexAV() {
+ if (pos + 4 >= length) {
+ // encoded byte array must be not less then 4 c
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+
+ beg = pos; // store '#' position
+ pos++;
+ while (true) {
+
+ // check for end of attribute value
+ // looks for space and component separators
+ if (pos == length || chars[pos] == '+' || chars[pos] == ','
+ || chars[pos] == ';') {
+ end = pos;
+ break;
+ }
+
+ if (chars[pos] == ' ') {
+ end = pos;
+ pos++;
+ // skip trailing space chars before comma or semicolon.
+ // (compatibility with RFC 1779)
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ }
+ break;
+ } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
+ chars[pos] += 32; //to low case
+ }
+
+ pos++;
+ }
+
+ // verify length of hex string
+ // encoded byte array must be not less then 4 and must be even number
+ int hexLen = end - beg; // skip first '#' char
+ if (hexLen < 5 || (hexLen & 1) == 0) {
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+
+ // get byte encoding from string representation
+ byte[] encoded = new byte[hexLen / 2];
+ for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
+ encoded[i] = (byte) getByte(p);
+ }
+
+ return new String(chars, beg, hexLen);
+ }
+
+ // gets string attribute value: *( stringchar / pair )
+ private String escapedAV() {
+ beg = pos;
+ end = pos;
+ while (true) {
+ if (pos >= length) {
+ // the end of DN has been found
+ return new String(chars, beg, end - beg);
+ }
+
+ switch (chars[pos]) {
+ case '+':
+ case ',':
+ case ';':
+ // separator char has beed found
+ return new String(chars, beg, end - beg);
+ case '\\':
+ // escaped char
+ chars[end++] = getEscaped();
+ pos++;
+ break;
+ case ' ':
+ // need to figure out whether space defines
+ // the end of attribute value or not
+ cur = end;
+
+ pos++;
+ chars[end++] = ' ';
+
+ for (; pos < length && chars[pos] == ' '; pos++) {
+ chars[end++] = ' ';
+ }
+ if (pos == length || chars[pos] == ',' || chars[pos] == '+'
+ || chars[pos] == ';') {
+ // separator char or the end of DN has beed found
+ return new String(chars, beg, cur - beg);
+ }
+ break;
+ default:
+ chars[end++] = chars[pos];
+ pos++;
+ }
+ }
+ }
+
+ // returns escaped char
+ private char getEscaped() {
+ pos++;
+ if (pos == length) {
+ throw new IllegalStateException("Unexpected end of DN: " + dn);
+ }
+
+ switch (chars[pos]) {
+ case '"':
+ case '\\':
+ case ',':
+ case '=':
+ case '+':
+ case '<':
+ case '>':
+ case '#':
+ case ';':
+ case ' ':
+ case '*':
+ case '%':
+ case '_':
+ //FIXME: escaping is allowed only for leading or trailing space char
+ return chars[pos];
+ default:
+ // RFC doesn't explicitly say that escaped hex pair is
+ // interpreted as UTF-8 char. It only contains an example of such DN.
+ return getUTF8();
+ }
+ }
+
+ // decodes UTF-8 char
+ // see http://www.unicode.org for UTF-8 bit distribution table
+ private char getUTF8() {
+ int res = getByte(pos);
+ pos++; //FIXME tmp
+
+ if (res < 128) { // one byte: 0-7F
+ return (char) res;
+ } else if (res >= 192 && res <= 247) {
+
+ int count;
+ if (res <= 223) { // two bytes: C0-DF
+ count = 1;
+ res = res & 0x1F;
+ } else if (res <= 239) { // three bytes: E0-EF
+ count = 2;
+ res = res & 0x0F;
+ } else { // four bytes: F0-F7
+ count = 3;
+ res = res & 0x07;
+ }
+
+ int b;
+ for (int i = 0; i < count; i++) {
+ pos++;
+ if (pos == length || chars[pos] != '\\') {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+ pos++;
+
+ b = getByte(pos);
+ pos++; //FIXME tmp
+ if ((b & 0xC0) != 0x80) {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+
+ res = (res << 6) + (b & 0x3F);
+ }
+ return (char) res;
+ } else {
+ return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+ }
+ }
+
+ // Returns byte representation of a char pair
+ // The char pair is composed of DN char in
+ // specified 'position' and the next char
+ // According to BNF syntax:
+ // hexchar = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+ // / "a" / "b" / "c" / "d" / "e" / "f"
+ private int getByte(int position) {
+ if (position + 1 >= length) {
+ throw new IllegalStateException("Malformed DN: " + dn);
+ }
+
+ int b1, b2;
+
+ b1 = chars[position];
+ if (b1 >= '0' && b1 <= '9') {
+ b1 = b1 - '0';
+ } else if (b1 >= 'a' && b1 <= 'f') {
+ b1 = b1 - 87; // 87 = 'a' - 10
+ } else if (b1 >= 'A' && b1 <= 'F') {
+ b1 = b1 - 55; // 55 = 'A' - 10
+ } else {
+ throw new IllegalStateException("Malformed DN: " + dn);
+ }
+
+ b2 = chars[position + 1];
+ if (b2 >= '0' && b2 <= '9') {
+ b2 = b2 - '0';
+ } else if (b2 >= 'a' && b2 <= 'f') {
+ b2 = b2 - 87; // 87 = 'a' - 10
+ } else if (b2 >= 'A' && b2 <= 'F') {
+ b2 = b2 - 55; // 55 = 'A' - 10
+ } else {
+ throw new IllegalStateException("Malformed DN: " + dn);
+ }
+
+ return (b1 << 4) + b2;
+ }
+
+ /**
+ * Parses the DN and returns the attribute value for an attribute type.
+ *
+ * @param attributeType attribute type to look for (e.g. "ca")
+ * @return value of the attribute that first found, or null if none found
+ */
+ public String find(String attributeType) {
+ // Initialize internal state.
+ pos = 0;
+ beg = 0;
+ end = 0;
+ cur = 0;
+ chars = dn.toCharArray();
+
+ String attType = nextAT();
+ if (attType == null) {
+ return null;
+ }
+ while (true) {
+ String attValue = "";
+
+ if (pos == length) {
+ return null;
+ }
+
+ switch (chars[pos]) {
+ case '"':
+ attValue = quotedAV();
+ break;
+ case '#':
+ attValue = hexAV();
+ break;
+ case '+':
+ case ',':
+ case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+ //empty attribute value
+ break;
+ default:
+ attValue = escapedAV();
+ }
+
+ if (attributeType.equalsIgnoreCase(attType)) {
+ return attValue;
+ }
+
+ if (pos >= length) {
+ return null;
+ }
+
+ if (chars[pos] == ',' || chars[pos] == ';') {
+ } else if (chars[pos] != '+') {
+ throw new IllegalStateException("Malformed DN: " + dn);
+ }
+
+ pos++;
+ attType = nextAT();
+ if (attType == null) {
+ throw new IllegalStateException("Malformed DN: " + dn);
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/javax/net/ssl/SSLSocket.java b/luni/src/main/java/javax/net/ssl/SSLSocket.java
index bc80b24..5049f81 100644
--- a/luni/src/main/java/javax/net/ssl/SSLSocket.java
+++ b/luni/src/main/java/javax/net/ssl/SSLSocket.java
@@ -24,7 +24,7 @@
/**
* The extension of {@code Socket} providing secure protocols like SSL (Secure
- * Socket Layer") or TLS (Transport Layer Security).
+ * Sockets Layer) or TLS (Transport Layer Security).
*/
public abstract class SSLSocket extends Socket {
diff --git a/luni/src/main/java/javax/net/ssl/package.html b/luni/src/main/java/javax/net/ssl/package.html
index 14753c8..ea6a701 100644
--- a/luni/src/main/java/javax/net/ssl/package.html
+++ b/luni/src/main/java/javax/net/ssl/package.html
@@ -5,15 +5,19 @@
<html>
<body>
<p>
-This package provides all the classes and interfaces needed to implement and program the Secure Socket
-abstraction based on the SSL protocol SSSLv3.0 or TLSv1.2.
-All the details of the SSL handshake protocol are accounted for, and a client or a server can specify the cipher
-set to use.
-
-X.509 certificates are verified, and, if desired, the client and the server each have the option of verifying
-the entire certificate chain until the root Certificate Authority is reached.
-
-Android uses code from The Legion of the Bouncy Castle (http://www.bouncycastle.org) and OpenSSL (http://openssl.org).
+This package provides classes and interfaces needed to use the Secure
+Sockets Layer (SSL) protocol and the successor Transport Layer
+Security (TLS) protocol. The API allows for both client and server
+sockets, the selection of desired SSL and TLS protocol versions, and
+the selection of desired cipher suites. The {@link
+javax.net.ssl.X509TrustManager X509TrustManager} interface allows
+customization of certificate chain verification. The
+{@link javax.net.ssl.X509KeyManager X509KeyManager} interface and
+{@link javax.net.ssl.X509ExtendedKeyManager X509ExtendedKeyManager}
+class allows the specification of a server's required certificate or a
+client's optional client certificate. Android uses code
+from <a href="http://www.bouncycastle.org">The Legion of the Bouncy
+Castle</a> and <a href="http://openssl.org">OpenSSL</a>.
</p>
</body>
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index b68730a..cb9c880 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -108,7 +108,7 @@
return localeData;
}
}
- LocaleData newLocaleData = makeLocaleData(locale);
+ LocaleData newLocaleData = initLocaleData(locale);
synchronized (localeDataCache) {
LocaleData localeData = localeDataCache.get(localeName);
if (localeData != null) {
@@ -119,24 +119,6 @@
}
}
- private static LocaleData makeLocaleData(Locale locale) {
- String language = locale.getLanguage();
- String country = locale.getCountry();
- String variant = locale.getVariant();
- // Start with data from the parent (next-most-specific) locale...
- LocaleData result = new LocaleData();
- if (!variant.isEmpty()) {
- result.overrideWithDataFrom(get(new Locale(language, country, "")));
- } else if (!country.isEmpty()) {
- result.overrideWithDataFrom(get(new Locale(language, "", "")));
- } else if (!language.isEmpty()) {
- result.overrideWithDataFrom(get(Locale.ROOT));
- }
- // Override with data from this locale.
- result.overrideWithDataFrom(initLocaleData(locale));
- return result;
- }
-
@Override public String toString() {
return "LocaleData[" +
"firstDayOfWeek=" + firstDayOfWeek + "," +
@@ -178,120 +160,6 @@
"percentPattern=" + percentPattern + "]";
}
- private void overrideWithDataFrom(LocaleData overrides) {
- if (overrides.firstDayOfWeek != null) {
- firstDayOfWeek = overrides.firstDayOfWeek;
- }
- if (overrides.minimalDaysInFirstWeek != null) {
- minimalDaysInFirstWeek = overrides.minimalDaysInFirstWeek;
- }
- if (overrides.amPm != null) {
- amPm = overrides.amPm;
- }
- if (overrides.eras != null) {
- eras = overrides.eras;
- }
- if (overrides.longMonthNames != null) {
- longMonthNames = overrides.longMonthNames;
- }
- if (overrides.shortMonthNames != null) {
- shortMonthNames = overrides.shortMonthNames;
- }
- if (overrides.longStandAloneMonthNames != null) {
- longStandAloneMonthNames = overrides.longStandAloneMonthNames;
- }
- if (overrides.shortStandAloneMonthNames != null) {
- shortStandAloneMonthNames = overrides.shortStandAloneMonthNames;
- }
- if (overrides.longWeekdayNames != null) {
- longWeekdayNames = overrides.longWeekdayNames;
- }
- if (overrides.shortWeekdayNames != null) {
- shortWeekdayNames = overrides.shortWeekdayNames;
- }
- if (overrides.longStandAloneWeekdayNames != null) {
- longStandAloneWeekdayNames = overrides.longStandAloneWeekdayNames;
- }
- if (overrides.shortStandAloneWeekdayNames != null) {
- shortStandAloneWeekdayNames = overrides.shortStandAloneWeekdayNames;
- }
- if (overrides.fullTimeFormat != null) {
- fullTimeFormat = overrides.fullTimeFormat;
- }
- if (overrides.longTimeFormat != null) {
- longTimeFormat = overrides.longTimeFormat;
- }
- if (overrides.mediumTimeFormat != null) {
- mediumTimeFormat = overrides.mediumTimeFormat;
- }
- if (overrides.shortTimeFormat != null) {
- shortTimeFormat = overrides.shortTimeFormat;
- }
- if (overrides.fullDateFormat != null) {
- fullDateFormat = overrides.fullDateFormat;
- }
- if (overrides.longDateFormat != null) {
- longDateFormat = overrides.longDateFormat;
- }
- if (overrides.mediumDateFormat != null) {
- mediumDateFormat = overrides.mediumDateFormat;
- }
- if (overrides.shortDateFormat != null) {
- shortDateFormat = overrides.shortDateFormat;
- }
- if (overrides.zeroDigit != '\0') {
- zeroDigit = overrides.zeroDigit;
- }
- if (overrides.decimalSeparator != '\0') {
- decimalSeparator = overrides.decimalSeparator;
- }
- if (overrides.groupingSeparator != '\0') {
- groupingSeparator = overrides.groupingSeparator;
- }
- if (overrides.patternSeparator != '\0') {
- patternSeparator = overrides.patternSeparator;
- }
- if (overrides.percent != '\0') {
- percent = overrides.percent;
- }
- if (overrides.perMill != '\0') {
- perMill = overrides.perMill;
- }
- if (overrides.monetarySeparator != '\0') {
- monetarySeparator = overrides.monetarySeparator;
- }
- if (overrides.minusSign != '\0') {
- minusSign = overrides.minusSign;
- }
- if (overrides.exponentSeparator != null) {
- exponentSeparator = overrides.exponentSeparator;
- }
- if (overrides.NaN != null) {
- NaN = overrides.NaN;
- }
- if (overrides.infinity != null) {
- infinity = overrides.infinity;
- }
- if (overrides.currencySymbol != null) {
- currencySymbol = overrides.currencySymbol;
- }
- if (overrides.internationalCurrencySymbol != null) {
- internationalCurrencySymbol = overrides.internationalCurrencySymbol;
- }
- if (overrides.numberPattern != null) {
- numberPattern = overrides.numberPattern;
- }
- if (overrides.integerPattern != null) {
- integerPattern = overrides.integerPattern;
- }
- if (overrides.currencyPattern != null) {
- currencyPattern = overrides.currencyPattern;
- }
- if (overrides.percentPattern != null) {
- percentPattern = overrides.percentPattern;
- }
- }
-
public String getDateFormat(int style) {
switch (style) {
case DateFormat.SHORT:
diff --git a/luni/src/main/java/libcore/io/DiskLruCache.java b/luni/src/main/java/libcore/io/DiskLruCache.java
index ecc1302..4699766 100644
--- a/luni/src/main/java/libcore/io/DiskLruCache.java
+++ b/luni/src/main/java/libcore/io/DiskLruCache.java
@@ -69,7 +69,7 @@
* <li>When an entry is being <strong>created</strong> it is necessary to
* supply a full set of values; the empty value should be used as a
* placeholder if necessary.
- * <li>When an entry is being <strong>created</strong>, it is not necessary
+ * <li>When an entry is being <strong>edited</strong>, it is not necessary
* to supply data for every value; values default to their previous
* value.
* </ul>
@@ -92,6 +92,7 @@
static final String JOURNAL_FILE_TMP = "journal.tmp";
static final String MAGIC = "libcore.io.DiskLruCache";
static final String VERSION_1 = "1";
+ static final long ANY_SEQUENCE_NUMBER = -1;
private static final String CLEAN = "CLEAN";
private static final String DIRTY = "DIRTY";
private static final String REMOVE = "REMOVE";
@@ -149,6 +150,13 @@
= new LinkedHashMap<String, Entry>(0, 0.75f, true);
private int redundantOpCount;
+ /**
+ * To differentiate between old and current snapshots, each entry is given
+ * a sequence number each time an edit is committed. A snapshot is stale if
+ * its sequence number is not equal to its entry's sequence number.
+ */
+ private long nextSequenceNumber = 0;
+
/** This cache uses a single background thread to evict entries. */
private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
@@ -382,22 +390,30 @@
executorService.submit(cleanupCallable);
}
- return new Snapshot(ins);
+ return new Snapshot(key, entry.sequenceNumber, ins);
}
/**
- * Returns an editor for the entry named {@code key}, or null if it cannot
- * currently be edited.
+ * Returns an editor for the entry named {@code key}, or null if another
+ * edit is in progress.
*/
- public synchronized Editor edit(String key) throws IOException {
+ public Editor edit(String key) throws IOException {
+ return edit(key, ANY_SEQUENCE_NUMBER);
+ }
+
+ private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
+ if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER
+ && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) {
+ return null; // snapshot is stale
+ }
if (entry == null) {
entry = new Entry(key);
lruEntries.put(key, entry);
} else if (entry.currentEditor != null) {
- return null;
+ return null; // another edit is in progress
}
Editor editor = new Editor(entry);
@@ -470,6 +486,9 @@
if (entry.readable | success) {
entry.readable = true;
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
+ if (success) {
+ entry.sequenceNumber = nextSequenceNumber++;
+ }
} else {
lruEntries.remove(entry.key);
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
@@ -594,14 +613,27 @@
/**
* A snapshot of the values for an entry.
*/
- public static final class Snapshot implements Closeable {
+ public final class Snapshot implements Closeable {
+ private final String key;
+ private final long sequenceNumber;
private final InputStream[] ins;
- private Snapshot(InputStream[] ins) {
+ private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
+ this.key = key;
+ this.sequenceNumber = sequenceNumber;
this.ins = ins;
}
/**
+ * Returns an editor for this snapshot's entry, or null if either the
+ * entry has changed since this snapshot was created or if another edit
+ * is in progress.
+ */
+ public Editor edit() throws IOException {
+ return DiskLruCache.this.edit(key, sequenceNumber);
+ }
+
+ /**
* Returns the unbuffered stream with the value for {@code index}.
*/
public InputStream getInputStream(int index) {
@@ -759,6 +791,9 @@
/** The ongoing edit or null if this entry is not being edited. */
private Editor currentEditor;
+ /** The sequence number of the most recently committed edit to this entry. */
+ private long sequenceNumber;
+
private Entry(String key) {
this.key = key;
this.lengths = new long[valueCount];
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index f95e8ec..2d60a86 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -128,32 +128,39 @@
return true;
}
- // With a timeout, we set the socket to non-blocking, connect(2), and then loop
- // using poll(2) to decide whether we're connected, whether we should keep waiting,
- // or whether we've seen a permanent failure and should give up.
- long finishTimeMs = System.currentTimeMillis() + timeoutMs;
+ // For connect with a timeout, we:
+ // 1. set the socket to non-blocking,
+ // 2. connect(2),
+ // 3. loop using poll(2) to decide whether we're connected, whether we should keep
+ // waiting, or whether we've seen a permanent failure and should give up,
+ // 4. set the socket back to blocking.
+
+ // 1. set the socket to non-blocking.
IoUtils.setBlocking(fd, false);
+
+ // 2. call connect(2) non-blocking.
+ long finishTimeMs = System.currentTimeMillis() + timeoutMs;
try {
- try {
- Libcore.os.connect(fd, inetAddress, port);
- return true; // We connected immediately.
- } catch (ErrnoException errnoException) {
- if (errnoException.errno != EINPROGRESS) {
- throw errnoException;
- }
- // EINPROGRESS means we should keep trying...
+ Libcore.os.connect(fd, inetAddress, port);
+ IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
+ return true; // We connected immediately.
+ } catch (ErrnoException errnoException) {
+ if (errnoException.errno != EINPROGRESS) {
+ throw errnoException;
}
- int remainingTimeoutMs;
- do {
- remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
- if (remainingTimeoutMs <= 0) {
- throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
- }
- } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
- return true; // Or we'd have thrown.
- } finally {
- IoUtils.setBlocking(fd, true);
+ // EINPROGRESS means we should keep trying...
}
+
+ // 3. loop using poll(2).
+ int remainingTimeoutMs;
+ do {
+ remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
+ if (remainingTimeoutMs <= 0) {
+ throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
+ }
+ } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
+ IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
+ return true; // Or we'd have thrown.
}
private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
@@ -200,6 +207,9 @@
}
throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
} catch (ErrnoException errnoException) {
+ if (!fd.valid()) {
+ throw new SocketException("Socket closed");
+ }
if (errnoException.errno == EINTR) {
return false; // Punt and ask the caller to try again.
} else {
@@ -209,8 +219,8 @@
// TODO: is it really helpful/necessary to throw so many different exceptions?
String detail = connectDetail(inetAddress, port, timeoutMs, cause);
if (cause.errno == ECONNRESET || cause.errno == ECONNREFUSED ||
- cause.errno == EADDRNOTAVAIL || cause.errno == EADDRINUSE ||
- cause.errno == ENETUNREACH) {
+ cause.errno == EADDRNOTAVAIL || cause.errno == EADDRINUSE ||
+ cause.errno == ENETUNREACH) {
throw new ConnectException(detail, cause);
} else if (cause.errno == EACCES) {
throw new SecurityException(detail, cause);
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index 4681bbc..6ea0baf 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -179,6 +179,7 @@
add("application/x-object", "o");
add("application/x-oz-application", "oza");
add("application/x-pkcs12", "p12");
+ add("application/x-pkcs12", "pfx");
add("application/x-pkcs7-certreqresp", "p7r");
add("application/x-pkcs7-crl", "crl");
add("application/x-quicktimeplayer", "qtl");
diff --git a/luni/src/main/java/libcore/net/RawSocket.java b/luni/src/main/java/libcore/net/RawSocket.java
index bb29fb0..08a7d09 100644
--- a/luni/src/main/java/libcore/net/RawSocket.java
+++ b/luni/src/main/java/libcore/net/RawSocket.java
@@ -32,35 +32,50 @@
* @hide
*/
public class RawSocket implements Closeable {
- private static native void create(FileDescriptor fd, String interfaceName)
+ /**
+ * Ethernet IP protocol type, part of the L2 header of IP packets.
+ */
+ public static final short ETH_P_IP = (short) 0x0800;
+
+ /**
+ * Ethernet ARP protocol type, part of the L2 header of ARP packets.
+ */
+ public static final short ETH_P_ARP = (short) 0x0806;
+
+ private static native void create(FileDescriptor fd, short
+ protocolType, String interfaceName)
throws SocketException;
private static native int sendPacket(FileDescriptor fd,
- String interfaceName, byte[] destMac, byte[] packet, int offset,
- int byteCount);
+ String interfaceName, short protocolType, byte[] destMac, byte[] packet,
+ int offset, int byteCount);
private static native int recvPacket(FileDescriptor fd, byte[] packet,
int offset, int byteCount, int destPort, int timeoutMillis);
private final FileDescriptor fd;
private final String mInterfaceName;
+ private final short mProtocolType;
private final CloseGuard guard = CloseGuard.get();
/**
* Creates a socket on the specified interface.
*/
- public RawSocket(String interfaceName) throws SocketException {
+ public RawSocket(String interfaceName, short protocolType)
+ throws SocketException {
mInterfaceName = interfaceName;
+ mProtocolType = protocolType;
fd = new FileDescriptor();
- create(fd, mInterfaceName);
+ create(fd, mProtocolType, mInterfaceName);
guard.open("close");
}
/**
* Reads a raw packet into the specified buffer, with the
- * specified timeout. Packets not destined for the desired UDP
- * port are discarded. Returns the length actually read. No
- * indication of overflow is signaled. The packet data will start
- * at the IP header (EthernetII dest/source/type headers are
- * removed).
+ * specified timeout. If the destPort is -1, then the IP
+ * destination port is not verified, otherwise only packets
+ * destined for the specified UDP port are returned. Returns the
+ * length actually read. No indication of overflow is signaled.
+ * The packet data will start at the IP header (EthernetII
+ * dest/source/type headers are removed).
*/
public int read(byte[] packet, int offset, int byteCount, int destPort,
int timeoutMillis) {
@@ -70,7 +85,7 @@
Arrays.checkOffsetAndCount(packet.length, offset, byteCount);
- if (destPort < 0 || destPort > 65535) {
+ if (destPort > 65535) {
throw new IllegalArgumentException("Port out of range: "
+ destPort);
}
@@ -82,8 +97,8 @@
/**
* Writes a raw packet to the desired interface. A L2 header will
* be added which includes the specified destination address, our
- * source MAC, and the IP type. The caller is responsible for
- * computing correct IP-header and payload checksums.
+ * source MAC, and the specified protocol type. The caller is responsible
+ * for computing correct IP-header and payload checksums.
*/
public int write(byte[] destMac, byte[] packet, int offset, int byteCount) {
if (destMac == null) {
@@ -101,8 +116,8 @@
+ destMac.length);
}
- return sendPacket(fd, mInterfaceName, destMac, packet, offset,
- byteCount);
+ return sendPacket(fd, mInterfaceName, mProtocolType, destMac, packet,
+ offset, byteCount);
}
/**
diff --git a/luni/src/main/java/libcore/net/UriCodec.java b/luni/src/main/java/libcore/net/UriCodec.java
index e11a014..bde922b 100644
--- a/luni/src/main/java/libcore/net/UriCodec.java
+++ b/luni/src/main/java/libcore/net/UriCodec.java
@@ -144,8 +144,12 @@
/**
* @param convertPlus true to convert '+' to ' '.
+ * @param throwOnFailure true to throw an IllegalArgumentException on
+ * invalid escape sequences; false to replace them with the replacement
+ * character (U+fffd).
*/
- public static String decode(String s, boolean convertPlus, Charset charset) {
+ public static String decode(String s, boolean convertPlus, Charset charset,
+ boolean throwOnFailure) {
if (s.indexOf('%') == -1 && (!convertPlus || s.indexOf('+') == -1)) {
return s;
}
@@ -156,16 +160,17 @@
char c = s.charAt(i);
if (c == '%') {
do {
- if (i + 2 >= s.length()) {
- throw new IllegalArgumentException("Incomplete % sequence at: " + i);
+ int d1, d2;
+ if (i + 2 < s.length()
+ && (d1 = hexToInt(s.charAt(i + 1))) != -1
+ && (d2 = hexToInt(s.charAt(i + 2))) != -1) {
+ out.write((byte) ((d1 << 4) + d2));
+ } else if (throwOnFailure) {
+ throw new IllegalArgumentException("Invalid % sequence at " + i + ": " + s);
+ } else {
+ byte[] replacement = "\ufffd".getBytes(charset);
+ out.write(replacement, 0, replacement.length);
}
- int d1 = hexToInt(s.charAt(i + 1));
- int d2 = hexToInt(s.charAt(i + 2));
- if (d1 == -1 || d2 == -1) {
- throw new IllegalArgumentException("Invalid % sequence " +
- s.substring(i, i + 3) + " at " + i);
- }
- out.write((byte) ((d1 << 4) + d2));
i += 3;
} while (i < s.length() && s.charAt(i) == '%');
result.append(new String(out.toByteArray(), charset));
@@ -198,7 +203,7 @@
}
public static String decode(String s) {
- return decode(s, false, Charsets.UTF_8);
+ return decode(s, false, Charsets.UTF_8, true);
}
private static void appendHex(StringBuilder builder, String s, Charset charset) {
diff --git a/luni/src/main/java/libcore/net/http/Challenge.java b/luni/src/main/java/libcore/net/http/Challenge.java
new file mode 100644
index 0000000..0326c17
--- /dev/null
+++ b/luni/src/main/java/libcore/net/http/Challenge.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 libcore.net.http;
+
+/**
+ * An RFC 2617 challenge.
+ *
+ * @hide
+ */
+public final class Challenge {
+ final String scheme;
+ final String realm;
+
+ public Challenge(String scheme, String realm) {
+ this.scheme = scheme;
+ this.realm = realm;
+ }
+
+ @Override public boolean equals(Object o) {
+ return o instanceof Challenge
+ && ((Challenge) o).scheme.equals(scheme)
+ && ((Challenge) o).realm.equals(realm);
+ }
+
+ @Override public int hashCode() {
+ return scheme.hashCode() + 31 * realm.hashCode();
+ }
+
+ @Override public String toString() {
+ return "Challenge[" + scheme + " " + realm + "]";
+ }
+}
diff --git a/luni/src/main/java/libcore/net/http/HeaderParser.java b/luni/src/main/java/libcore/net/http/HeaderParser.java
index 31e09f9..8d5770e 100644
--- a/luni/src/main/java/libcore/net/http/HeaderParser.java
+++ b/luni/src/main/java/libcore/net/http/HeaderParser.java
@@ -16,7 +16,13 @@
package libcore.net.http;
-final class HeaderParser {
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class HeaderParser {
public interface CacheControlHandler {
void handle(String directive, String parameter);
@@ -63,6 +69,55 @@
}
/**
+ * Parse RFC 2617 challenges. This API is only interested in the scheme
+ * name and realm.
+ */
+ public static List<Challenge> parseChallenges(
+ RawHeaders responseHeaders, String challengeHeader) {
+ /*
+ * auth-scheme = token
+ * auth-param = token "=" ( token | quoted-string )
+ * challenge = auth-scheme 1*SP 1#auth-param
+ * realm = "realm" "=" realm-value
+ * realm-value = quoted-string
+ */
+ List<Challenge> result = new ArrayList<Challenge>();
+ for (int h = 0; h < responseHeaders.length(); h++) {
+ if (!challengeHeader.equalsIgnoreCase(responseHeaders.getFieldName(h))) {
+ continue;
+ }
+ String value = responseHeaders.getValue(h);
+ int pos = 0;
+ while (pos < value.length()) {
+ int tokenStart = pos;
+ pos = skipUntil(value, pos, " ");
+
+ String scheme = value.substring(tokenStart, pos).trim();
+ pos = skipWhitespace(value, pos);
+
+ // TODO: This currently only handles schemes with a 'realm' parameter;
+ // It needs to be fixed to handle any scheme and any parameters
+ // http://code.google.com/p/android/issues/detail?id=11140
+
+ if (!value.regionMatches(pos, "realm=\"", 0, "realm=\"".length())) {
+ break; // unexpected challenge parameter; give up
+ }
+
+ pos += "realm=\"".length();
+ int realmStart = pos;
+ pos = skipUntil(value, pos, "\"");
+ String realm = value.substring(realmStart, pos);
+ pos++; // consume '"' close quote
+ pos = skipUntil(value, pos, ",");
+ pos++; // consume ',' comma
+ pos = skipWhitespace(value, pos);
+ result.add(new Challenge(scheme, realm));
+ }
+ }
+ return result;
+ }
+
+ /**
* Returns the next index in {@code input} at or after {@code pos} that
* contains a character from {@code characters}. Returns the input length if
* none of the requested characters can be found.
diff --git a/luni/src/main/java/libcore/net/http/HttpConnection.java b/luni/src/main/java/libcore/net/http/HttpConnection.java
index 756edb8..66dec4d 100644
--- a/luni/src/main/java/libcore/net/http/HttpConnection.java
+++ b/luni/src/main/java/libcore/net/http/HttpConnection.java
@@ -28,8 +28,8 @@
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
-import java.net.SocketTimeoutException;
import java.net.URI;
+import java.net.UnknownHostException;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocket;
@@ -49,15 +49,14 @@
*/
final class HttpConnection {
private final Address address;
-
private final Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
-
private SSLSocket unverifiedSocket;
private SSLSocket sslSocket;
private InputStream sslInputStream;
private OutputStream sslOutputStream;
+ private boolean recycled = false;
private HttpConnection(Address config, int connectTimeout) throws IOException {
this.address = config;
@@ -87,15 +86,15 @@
this.socket = socketCandidate;
}
- public static HttpConnection connect(URI uri, Proxy proxy, boolean requiresTunnel,
- int connectTimeout) throws IOException {
+ public static HttpConnection connect(URI uri, SSLSocketFactory sslSocketFactory,
+ Proxy proxy, boolean requiresTunnel, int connectTimeout) throws IOException {
/*
* Try an explicitly-specified proxy.
*/
if (proxy != null) {
Address address = (proxy.type() == Proxy.Type.DIRECT)
- ? new Address(uri)
- : new Address(uri, proxy, requiresTunnel);
+ ? new Address(uri, sslSocketFactory)
+ : new Address(uri, sslSocketFactory, proxy, requiresTunnel);
return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
}
@@ -113,7 +112,8 @@
continue;
}
try {
- Address address = new Address(uri, selectedProxy, requiresTunnel);
+ Address address = new Address(uri, sslSocketFactory,
+ selectedProxy, requiresTunnel);
return HttpConnectionPool.INSTANCE.get(address, connectTimeout);
} catch (IOException e) {
// failed to connect, tell it to the selector
@@ -125,7 +125,7 @@
/*
* Try a direct connection. If this fails, this method will throw.
*/
- return HttpConnectionPool.INSTANCE.get(new Address(uri), connectTimeout);
+ return HttpConnectionPool.INSTANCE.get(new Address(uri, sslSocketFactory), connectTimeout);
}
public void closeSocketAndStreams() {
@@ -235,43 +235,20 @@
}
/**
- * Returns true if the connection is functional. This uses a shameful hack
- * to peek a byte from the socket.
+ * Returns true if this connection has been used to satisfy an earlier
+ * HTTP request/response pair.
*/
- boolean isStale() throws IOException {
- if (!isEligibleForRecycling()) {
- return true;
- }
+ public boolean isRecycled() {
+ return recycled;
+ }
- InputStream in = getInputStream();
- if (in.available() > 0) {
- return false;
- }
-
- Socket socket = getSocket();
- int soTimeout = socket.getSoTimeout();
- try {
- socket.setSoTimeout(1);
- in.mark(1);
- int byteRead = in.read();
- if (byteRead != -1) {
- in.reset();
- return false;
- }
- return true; // the socket is reporting all data read; it's stale
- } catch (SocketTimeoutException e) {
- return false; // the connection is not stale; hooray
- } catch (IOException e) {
- return true; // the connection is stale, the read or soTimeout failed.
- } finally {
- socket.setSoTimeout(soTimeout);
- }
+ public void setRecycled() {
+ this.recycled = true;
}
/**
- * Returns true if this connection is eligible to be recycled. This
- * is like {@link #isStale} except that it doesn't try to actually
- * perform any I/O.
+ * Returns true if this connection is eligible to be reused for another
+ * request/response pair.
*/
protected boolean isEligibleForRecycling() {
return !socket.isClosed()
@@ -282,7 +259,8 @@
/**
* This address has two parts: the address we connect to directly and the
* origin address of the resource. These are the same unless a proxy is
- * being used.
+ * being used. It also includes the SSL socket factory so that a socket will
+ * not be reused if its SSL configuration is different.
*/
public static final class Address {
private final Proxy proxy;
@@ -291,14 +269,19 @@
private final int uriPort;
private final String socketHost;
private final int socketPort;
+ private final SSLSocketFactory sslSocketFactory;
- public Address(URI uri) {
+ public Address(URI uri, SSLSocketFactory sslSocketFactory) throws UnknownHostException {
this.proxy = null;
this.requiresTunnel = false;
this.uriHost = uri.getHost();
this.uriPort = uri.getEffectivePort();
+ this.sslSocketFactory = sslSocketFactory;
this.socketHost = uriHost;
this.socketPort = uriPort;
+ if (uriHost == null) {
+ throw new UnknownHostException(uri.toString());
+ }
}
/**
@@ -307,11 +290,13 @@
* proxy. When doing so, we must avoid buffering bytes intended for
* the higher-level protocol.
*/
- public Address(URI uri, Proxy proxy, boolean requiresTunnel) {
+ public Address(URI uri, SSLSocketFactory sslSocketFactory,
+ Proxy proxy, boolean requiresTunnel) throws UnknownHostException {
this.proxy = proxy;
this.requiresTunnel = requiresTunnel;
this.uriHost = uri.getHost();
this.uriPort = uri.getEffectivePort();
+ this.sslSocketFactory = sslSocketFactory;
SocketAddress proxyAddress = proxy.address();
if (!(proxyAddress instanceof InetSocketAddress)) {
@@ -321,6 +306,9 @@
InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;
this.socketHost = proxySocketAddress.getHostName();
this.socketPort = proxySocketAddress.getPort();
+ if (uriHost == null) {
+ throw new UnknownHostException(uri.toString());
+ }
}
public Proxy getProxy() {
@@ -333,6 +321,7 @@
return Objects.equal(this.proxy, that.proxy)
&& this.uriHost.equals(that.uriHost)
&& this.uriPort == that.uriPort
+ && Objects.equal(this.sslSocketFactory, that.sslSocketFactory)
&& this.requiresTunnel == that.requiresTunnel;
}
return false;
@@ -342,6 +331,7 @@
int result = 17;
result = 31 * result + uriHost.hashCode();
result = 31 * result + uriPort;
+ result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0);
result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
result = 31 * result + (requiresTunnel ? 1 : 0);
return result;
diff --git a/luni/src/main/java/libcore/net/http/HttpConnectionPool.java b/luni/src/main/java/libcore/net/http/HttpConnectionPool.java
index 21e94de..1f5f4d9 100644
--- a/luni/src/main/java/libcore/net/http/HttpConnectionPool.java
+++ b/luni/src/main/java/libcore/net/http/HttpConnectionPool.java
@@ -65,17 +65,18 @@
// First try to reuse an existing HTTP connection.
synchronized (connectionPool) {
List<HttpConnection> connections = connectionPool.get(address);
- if (connections != null) {
- while (!connections.isEmpty()) {
- HttpConnection connection = connections.remove(connections.size() - 1);
- if (!connection.isStale()) { // TODO: this op does I/O!
- // Since Socket is recycled, re-tag before using
- final Socket socket = connection.getSocket();
- SocketTagger.get().tag(socket);
- return connection;
- }
+ while (connections != null) {
+ HttpConnection connection = connections.remove(connections.size() - 1);
+ if (connections.isEmpty()) {
+ connectionPool.remove(address);
+ connections = null;
}
- connectionPool.remove(address);
+ if (connection.isEligibleForRecycling()) {
+ // Since Socket is recycled, re-tag before using
+ Socket socket = connection.getSocket();
+ SocketTagger.get().tag(socket);
+ return connection;
+ }
}
}
@@ -87,7 +88,7 @@
}
public void recycle(HttpConnection connection) {
- final Socket socket = connection.getSocket();
+ Socket socket = connection.getSocket();
try {
SocketTagger.get().untag(socket);
} catch (SocketException e) {
@@ -106,6 +107,7 @@
connectionPool.put(address, connections);
}
if (connections.size() < maxConnections) {
+ connection.setRecycled();
connections.add(connection);
return; // keep the connection open
}
diff --git a/luni/src/main/java/libcore/net/http/HttpEngine.java b/luni/src/main/java/libcore/net/http/HttpEngine.java
index 25f28f5..3e4b9d3 100644
--- a/luni/src/main/java/libcore/net/http/HttpEngine.java
+++ b/luni/src/main/java/libcore/net/http/HttpEngine.java
@@ -25,9 +25,11 @@
import java.net.CacheRequest;
import java.net.CacheResponse;
import java.net.CookieHandler;
+import java.net.ExtendedResponseCache;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.ResponseCache;
+import java.net.ResponseSource;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
@@ -38,6 +40,7 @@
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
+import javax.net.ssl.SSLSocketFactory;
import libcore.io.IoUtils;
import libcore.io.Streams;
import libcore.util.EmptyArray;
@@ -197,6 +200,10 @@
this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders));
}
+ public URI getUri() {
+ return uri;
+ }
+
/**
* Figures out what the response source will be, and opens a socket to that
* source if necessary. Prepares the request headers and gets ready to start
@@ -209,8 +216,8 @@
prepareRawRequestHeaders();
initResponseSource();
- if (responseCache instanceof HttpResponseCache) {
- ((HttpResponseCache) responseCache).trackResponse(responseSource);
+ if (responseCache instanceof ExtendedResponseCache) {
+ ((ExtendedResponseCache) responseCache).trackResponse(responseSource);
}
/*
@@ -305,8 +312,8 @@
}
protected final HttpConnection openSocketConnection() throws IOException {
- HttpConnection result = HttpConnection.connect(
- uri, policy.getProxy(), requiresTunnel(), policy.getConnectTimeout());
+ HttpConnection result = HttpConnection.connect(uri, getSslSocketFactory(),
+ policy.getProxy(), requiresTunnel(), policy.getConnectTimeout());
Proxy proxy = result.getAddress().getProxy();
if (proxy != null) {
policy.setProxy(proxy);
@@ -415,6 +422,10 @@
return connection;
}
+ public final boolean hasRecycledConnection() {
+ return connection != null && connection.isRecycled();
+ }
+
/**
* Returns true if {@code cacheResponse} is of the right type. This
* condition is necessary but not sufficient for the cached response to
@@ -425,6 +436,11 @@
}
private void maybeCache() throws IOException {
+ // Never cache responses to proxy CONNECT requests.
+ if (method == CONNECT) {
+ return;
+ }
+
// Are we caching at all?
if (!policy.getUseCaches() || responseCache == null) {
return;
@@ -553,8 +569,13 @@
*/
public final boolean hasResponseBody() {
int responseCode = responseHeaders.getHeaders().getResponseCode();
- if (method != HEAD
- && method != CONNECT
+
+ // HEAD requests never yield a body regardless of the response headers.
+ if (method == HEAD) {
+ return false;
+ }
+
+ if (method != CONNECT
&& (responseCode < HTTP_CONTINUE || responseCode >= 200)
&& responseCode != HttpURLConnectionImpl.HTTP_NO_CONTENT
&& responseCode != HttpURLConnectionImpl.HTTP_NOT_MODIFIED) {
@@ -724,6 +745,14 @@
return policy.usingProxy();
}
+ /**
+ * Returns the SSL configuration for connections created by this engine.
+ * We cannot reuse HTTPS connections if the socket factory has changed.
+ */
+ protected SSLSocketFactory getSslSocketFactory() {
+ return null;
+ }
+
protected final String getDefaultUserAgent() {
String agent = System.getProperty("http.agent");
return agent != null ? agent : ("Java" + System.getProperty("java.version"));
@@ -786,12 +815,14 @@
if (responseSource == ResponseSource.CONDITIONAL_CACHE) {
if (cachedResponseHeaders.validate(responseHeaders)) {
- if (responseCache instanceof HttpResponseCache) {
- ((HttpResponseCache) responseCache).trackConditionalCacheHit();
- }
- // Discard the network response body. Combine the headers.
release(true);
- setResponse(cachedResponseHeaders.combine(responseHeaders), cachedResponseBody);
+ ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders);
+ setResponse(combinedHeaders, cachedResponseBody);
+ if (responseCache instanceof ExtendedResponseCache) {
+ ExtendedResponseCache httpResponseCache = (ExtendedResponseCache) responseCache;
+ httpResponseCache.trackConditionalCacheHit();
+ httpResponseCache.update(cacheResponse, getHttpConnectionToCache());
+ }
return;
} else {
IoUtils.closeQuietly(cachedResponseBody);
diff --git a/luni/src/main/java/libcore/net/http/HttpResponseCache.java b/luni/src/main/java/libcore/net/http/HttpResponseCache.java
index 24aff87..910461e7 100644
--- a/luni/src/main/java/libcore/net/http/HttpResponseCache.java
+++ b/luni/src/main/java/libcore/net/http/HttpResponseCache.java
@@ -29,8 +29,10 @@
import java.io.Writer;
import java.net.CacheRequest;
import java.net.CacheResponse;
+import java.net.ExtendedResponseCache;
import java.net.HttpURLConnection;
import java.net.ResponseCache;
+import java.net.ResponseSource;
import java.net.SecureCacheResponse;
import java.net.URI;
import java.net.URLConnection;
@@ -58,7 +60,7 @@
* {@code android.net.HttpResponseCache}, the stable, documented front end for
* this.
*/
-public final class HttpResponseCache extends ResponseCache {
+public final class HttpResponseCache extends ResponseCache implements ExtendedResponseCache {
// TODO: add APIs to iterate the cache?
private static final int VERSION = 201105;
private static final int ENTRY_METADATA = 0;
@@ -109,23 +111,9 @@
return null;
}
- InputStream body = newBodyInputStream(snapshot);
return entry.isHttps()
- ? entry.newSecureCacheResponse(body)
- : entry.newCacheResponse(body);
- }
-
- /**
- * Returns an input stream that reads the body of a snapshot, closing the
- * snapshot when the stream is closed.
- */
- private InputStream newBodyInputStream(final DiskLruCache.Snapshot snapshot) {
- return new FilterInputStream(snapshot.getInputStream(ENTRY_BODY)) {
- @Override public void close() throws IOException {
- snapshot.close();
- super.close();
- }
- };
+ ? new EntrySecureCacheResponse(entry, snapshot)
+ : new EntryCacheResponse(entry, snapshot);
}
@Override public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException {
@@ -178,17 +166,49 @@
entry.writeTo(editor);
return new CacheRequestImpl(editor);
} catch (IOException e) {
- // Give up because the cache cannot be written.
- try {
- if (editor != null) {
- editor.abort();
- }
- } catch (IOException ignored) {
- }
+ abortQuietly(editor);
return null;
}
}
+ /**
+ * Handles a conditional request hit by updating the stored cache response
+ * with the headers from {@code httpConnection}. The cached response body is
+ * not updated. If the stored response has changed since {@code
+ * conditionalCacheHit} was returned, this does nothing.
+ */
+ public void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection) {
+ HttpEngine httpEngine = getHttpEngine(httpConnection);
+ URI uri = httpEngine.getUri();
+ ResponseHeaders response = httpEngine.getResponseHeaders();
+ RawHeaders varyHeaders = httpEngine.getRequestHeaders().getHeaders()
+ .getAll(response.getVaryFields());
+ Entry entry = new Entry(uri, varyHeaders, httpConnection);
+ DiskLruCache.Snapshot snapshot = (conditionalCacheHit instanceof EntryCacheResponse)
+ ? ((EntryCacheResponse) conditionalCacheHit).snapshot
+ : ((EntrySecureCacheResponse) conditionalCacheHit).snapshot;
+ DiskLruCache.Editor editor = null;
+ try {
+ editor = snapshot.edit(); // returns null if snapshot is not current
+ if (editor != null) {
+ entry.writeTo(editor);
+ editor.commit();
+ }
+ } catch (IOException e) {
+ abortQuietly(editor);
+ }
+ }
+
+ private void abortQuietly(DiskLruCache.Editor editor) {
+ // Give up because the cache cannot be written.
+ try {
+ if (editor != null) {
+ editor.abort();
+ }
+ } catch (IOException ignored) {
+ }
+ }
+
private HttpEngine getHttpEngine(HttpURLConnection httpConnection) {
if (httpConnection instanceof HttpURLConnectionImpl) {
return ((HttpURLConnectionImpl) httpConnection).getHttpEngine();
@@ -211,7 +231,7 @@
return writeSuccessCount;
}
- synchronized void trackResponse(ResponseSource source) {
+ public synchronized void trackResponse(ResponseSource source) {
requestCount++;
switch (source) {
@@ -225,7 +245,7 @@
}
}
- synchronized void trackConditionalCacheHit() {
+ public synchronized void trackConditionalCacheHit() {
hitCount++;
}
@@ -490,62 +510,91 @@
&& new ResponseHeaders(uri, responseHeaders)
.varyMatches(varyHeaders.toMultimap(), requestHeaders);
}
+ }
- public CacheResponse newCacheResponse(final InputStream in) {
- return new CacheResponse() {
- @Override public Map<String, List<String>> getHeaders() {
- return responseHeaders.toMultimap();
- }
+ /**
+ * Returns an input stream that reads the body of a snapshot, closing the
+ * snapshot when the stream is closed.
+ */
+ private static InputStream newBodyInputStream(final DiskLruCache.Snapshot snapshot) {
+ return new FilterInputStream(snapshot.getInputStream(ENTRY_BODY)) {
+ @Override public void close() throws IOException {
+ snapshot.close();
+ super.close();
+ }
+ };
+ }
- @Override public InputStream getBody() {
- return in;
- }
- };
+ static class EntryCacheResponse extends CacheResponse {
+ private final Entry entry;
+ private final DiskLruCache.Snapshot snapshot;
+ private final InputStream in;
+
+ public EntryCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
+ this.entry = entry;
+ this.snapshot = snapshot;
+ this.in = newBodyInputStream(snapshot);
}
- public SecureCacheResponse newSecureCacheResponse(final InputStream in) {
- return new SecureCacheResponse() {
- @Override public Map<String, List<String>> getHeaders() {
- return responseHeaders.toMultimap();
- }
+ @Override public Map<String, List<String>> getHeaders() {
+ return entry.responseHeaders.toMultimap();
+ }
- @Override public InputStream getBody() {
- return in;
- }
+ @Override public InputStream getBody() {
+ return in;
+ }
+ }
- @Override public String getCipherSuite() {
- return cipherSuite;
- }
+ static class EntrySecureCacheResponse extends SecureCacheResponse {
+ private final Entry entry;
+ private final DiskLruCache.Snapshot snapshot;
+ private final InputStream in;
- @Override public List<Certificate> getServerCertificateChain()
- throws SSLPeerUnverifiedException {
- if (peerCertificates == null || peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException(null);
- }
- return Arrays.asList(peerCertificates.clone());
- }
+ public EntrySecureCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) {
+ this.entry = entry;
+ this.snapshot = snapshot;
+ this.in = newBodyInputStream(snapshot);
+ }
- @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- if (peerCertificates == null || peerCertificates.length == 0) {
- throw new SSLPeerUnverifiedException(null);
- }
- return ((X509Certificate) peerCertificates[0]).getSubjectX500Principal();
- }
+ @Override public Map<String, List<String>> getHeaders() {
+ return entry.responseHeaders.toMultimap();
+ }
- @Override public List<Certificate> getLocalCertificateChain() {
- if (localCertificates == null || localCertificates.length == 0) {
- return null;
- }
- return Arrays.asList(localCertificates.clone());
- }
+ @Override public InputStream getBody() {
+ return in;
+ }
- @Override public Principal getLocalPrincipal() {
- if (localCertificates == null || localCertificates.length == 0) {
- return null;
- }
- return ((X509Certificate) localCertificates[0]).getSubjectX500Principal();
- }
- };
+ @Override public String getCipherSuite() {
+ return entry.cipherSuite;
+ }
+
+ @Override public List<Certificate> getServerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException(null);
+ }
+ return Arrays.asList(entry.peerCertificates.clone());
+ }
+
+ @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ if (entry.peerCertificates == null || entry.peerCertificates.length == 0) {
+ throw new SSLPeerUnverifiedException(null);
+ }
+ return ((X509Certificate) entry.peerCertificates[0]).getSubjectX500Principal();
+ }
+
+ @Override public List<Certificate> getLocalCertificateChain() {
+ if (entry.localCertificates == null || entry.localCertificates.length == 0) {
+ return null;
+ }
+ return Arrays.asList(entry.localCertificates.clone());
+ }
+
+ @Override public Principal getLocalPrincipal() {
+ if (entry.localCertificates == null || entry.localCertificates.length == 0) {
+ return null;
+ }
+ return ((X509Certificate) entry.localCertificates[0]).getSubjectX500Principal();
}
}
}
diff --git a/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java b/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
index 8dbaf8c..a59df55 100644
--- a/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
+++ b/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java
@@ -268,53 +268,64 @@
return httpEngine;
}
- try {
- while (true) {
+ while (true) {
+ try {
httpEngine.sendRequest();
httpEngine.readResponse();
-
- Retry retry = processResponseHeaders();
- if (retry == Retry.NONE) {
- httpEngine.automaticallyReleaseConnectionToPool();
- break;
- }
-
+ } catch (IOException e) {
/*
- * The first request was insufficient. Prepare for another...
+ * If the connection was recycled, its staleness may have caused
+ * the failure. Silently retry with a different connection.
*/
- String retryMethod = method;
OutputStream requestBody = httpEngine.getRequestBody();
-
- /*
- * Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM
- * redirect should keep the same method, Chrome, Firefox and the
- * RI all issue GETs when following any redirect.
- */
- int responseCode = getResponseCode();
- if (responseCode == HTTP_MULT_CHOICE || responseCode == HTTP_MOVED_PERM
- || responseCode == HTTP_MOVED_TEMP || responseCode == HTTP_SEE_OTHER) {
- retryMethod = HttpEngine.GET;
- requestBody = null;
+ if (httpEngine.hasRecycledConnection()
+ && (requestBody == null || requestBody instanceof RetryableOutputStream)) {
+ httpEngine.release(false);
+ httpEngine = newHttpEngine(method, rawRequestHeaders, null,
+ (RetryableOutputStream) requestBody);
+ continue;
}
-
- if (requestBody != null && !(requestBody instanceof RetryableOutputStream)) {
- throw new HttpRetryException("Cannot retry streamed HTTP body",
- httpEngine.getResponseCode());
- }
-
- if (retry == Retry.DIFFERENT_CONNECTION) {
- httpEngine.automaticallyReleaseConnectionToPool();
- }
-
- httpEngine.release(true);
-
- httpEngine = newHttpEngine(retryMethod, rawRequestHeaders,
- httpEngine.getConnection(), (RetryableOutputStream) requestBody);
+ httpEngineFailure = e;
+ throw e;
}
- return httpEngine;
- } catch (IOException e) {
- httpEngineFailure = e;
- throw e;
+
+ Retry retry = processResponseHeaders();
+ if (retry == Retry.NONE) {
+ httpEngine.automaticallyReleaseConnectionToPool();
+ return httpEngine;
+ }
+
+ /*
+ * The first request was insufficient. Prepare for another...
+ */
+ String retryMethod = method;
+ OutputStream requestBody = httpEngine.getRequestBody();
+
+ /*
+ * Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM
+ * redirect should keep the same method, Chrome, Firefox and the
+ * RI all issue GETs when following any redirect.
+ */
+ int responseCode = getResponseCode();
+ if (responseCode == HTTP_MULT_CHOICE || responseCode == HTTP_MOVED_PERM
+ || responseCode == HTTP_MOVED_TEMP || responseCode == HTTP_SEE_OTHER) {
+ retryMethod = HttpEngine.GET;
+ requestBody = null;
+ }
+
+ if (requestBody != null && !(requestBody instanceof RetryableOutputStream)) {
+ throw new HttpRetryException("Cannot retry streamed HTTP body",
+ httpEngine.getResponseCode());
+ }
+
+ if (retry == Retry.DIFFERENT_CONNECTION) {
+ httpEngine.automaticallyReleaseConnectionToPool();
+ }
+
+ httpEngine.release(true);
+
+ httpEngine = newHttpEngine(retryMethod, rawRequestHeaders,
+ httpEngine.getConnection(), (RetryableOutputStream) requestBody);
}
}
@@ -390,13 +401,10 @@
}
// keep asking for username/password until authorized
- String challenge = responseCode == HTTP_PROXY_AUTH
- ? response.getProxyAuthenticate()
- : response.getWwwAuthenticate();
- if (challenge == null) {
- throw new IOException("Received authentication challenge is null");
- }
- String credentials = getAuthorizationCredentials(challenge);
+ String challengeHeader = responseCode == HTTP_PROXY_AUTH
+ ? "Proxy-Authenticate"
+ : "WWW-Authenticate";
+ String credentials = getAuthorizationCredentials(response.getHeaders(), challengeHeader);
if (credentials == null) {
return false; // could not find credentials, end request cycle
}
@@ -412,31 +420,30 @@
/**
* Returns the authorization credentials on the base of provided challenge.
*/
- private String getAuthorizationCredentials(String challenge) throws IOException {
- int idx = challenge.indexOf(" ");
- if (idx == -1) {
- return null;
+ private String getAuthorizationCredentials(RawHeaders responseHeaders, String challengeHeader)
+ throws IOException {
+ List<Challenge> challenges = HeaderParser.parseChallenges(responseHeaders, challengeHeader);
+ if (challenges.isEmpty()) {
+ throw new IOException("No authentication challenges found");
}
- String scheme = challenge.substring(0, idx);
- int realm = challenge.indexOf("realm=\"") + 7;
- String prompt = null;
- if (realm != -1) {
- int end = challenge.indexOf('"', realm);
- if (end != -1) {
- prompt = challenge.substring(realm, end);
+
+ for (Challenge challenge : challenges) {
+ // use the global authenticator to get the password
+ PasswordAuthentication auth = Authenticator.requestPasswordAuthentication(
+ getConnectToInetAddress(), getConnectToPort(), url.getProtocol(),
+ challenge.realm, challenge.scheme);
+ if (auth == null) {
+ continue;
}
+
+ // base64 encode the username and password
+ String usernameAndPassword = auth.getUserName() + ":" + new String(auth.getPassword());
+ byte[] bytes = usernameAndPassword.getBytes(Charsets.ISO_8859_1);
+ String encoded = Base64.encode(bytes);
+ return challenge.scheme + " " + encoded;
}
- // use the global authenticator to get the password
- PasswordAuthentication pa = Authenticator.requestPasswordAuthentication(
- getConnectToInetAddress(), getConnectToPort(), url.getProtocol(), prompt, scheme);
- if (pa == null) {
- return null;
- }
- // base64 encode the username and password
- String usernameAndPassword = pa.getUserName() + ":" + new String(pa.getPassword());
- byte[] bytes = usernameAndPassword.getBytes(Charsets.ISO_8859_1);
- String encoded = Base64.encode(bytes);
- return scheme + " " + encoded;
+
+ return null;
}
private InetAddress getConnectToInetAddress() throws IOException {
diff --git a/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java b/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
index ae5e7c1..9e3e4ef 100644
--- a/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
+++ b/luni/src/main/java/libcore/net/http/HttpsURLConnectionImpl.java
@@ -35,6 +35,7 @@
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
final class HttpsURLConnectionImpl extends HttpsURLConnection {
@@ -336,8 +337,8 @@
}
@Override
- public void setConnectTimeout(int timeout) {
- delegate.setConnectTimeout(timeout);
+ public void setConnectTimeout(int timeoutMillis) {
+ delegate.setConnectTimeout(timeoutMillis);
}
@Override
@@ -346,8 +347,8 @@
}
@Override
- public void setReadTimeout(int timeout) {
- delegate.setReadTimeout(timeout);
+ public void setReadTimeout(int timeoutMillis) {
+ delegate.setReadTimeout(timeoutMillis);
}
@Override
@@ -519,6 +520,10 @@
return false;
}
+ @Override protected SSLSocketFactory getSslSocketFactory() {
+ return enclosing.getSSLSocketFactory();
+ }
+
@Override protected HttpURLConnection getHttpConnectionToCache() {
return enclosing;
}
diff --git a/luni/src/main/java/libcore/net/http/ResponseHeaders.java b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
index 0d8cc40..003b445 100644
--- a/luni/src/main/java/libcore/net/http/ResponseHeaders.java
+++ b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
@@ -17,6 +17,7 @@
package libcore.net.http;
import java.net.HttpURLConnection;
+import java.net.ResponseSource;
import java.net.URI;
import java.util.Collections;
import java.util.Date;
@@ -108,8 +109,6 @@
private String transferEncoding;
private int contentLength = -1;
private String connection;
- private String proxyAuthenticate;
- private String wwwAuthenticate;
public ResponseHeaders(URI uri, RawHeaders headers) {
this.uri = uri;
@@ -171,10 +170,6 @@
}
} else if ("Connection".equalsIgnoreCase(fieldName)) {
connection = value;
- } else if ("Proxy-Authenticate".equalsIgnoreCase(fieldName)) {
- proxyAuthenticate = value;
- } else if ("WWW-Authenticate".equalsIgnoreCase(fieldName)) {
- wwwAuthenticate = value;
} else if (SENT_MILLIS.equalsIgnoreCase(fieldName)) {
sentRequestMillis = Long.parseLong(value);
} else if (RECEIVED_MILLIS.equalsIgnoreCase(fieldName)) {
@@ -264,14 +259,6 @@
return connection;
}
- public String getProxyAuthenticate() {
- return proxyAuthenticate;
- }
-
- public String getWwwAuthenticate() {
- return wwwAuthenticate;
- }
-
public void setLocalTimestamps(long sentRequestMillis, long receivedResponseMillis) {
this.sentRequestMillis = sentRequestMillis;
headers.add(SENT_MILLIS, Long.toString(sentRequestMillis));
@@ -476,6 +463,7 @@
*/
public ResponseHeaders combine(ResponseHeaders network) {
RawHeaders result = new RawHeaders();
+ result.setStatusLine(headers.getStatusLine());
for (int i = 0; i < headers.length(); i++) {
String fieldName = headers.getFieldName(i);
diff --git a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
index e6adc44..b15e8ac 100644
--- a/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
+++ b/luni/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
@@ -38,7 +38,6 @@
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPublicKey;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -49,7 +48,7 @@
import org.apache.harmony.security.x509.Extension;
import org.apache.harmony.security.x509.Extensions;
import org.apache.harmony.security.x509.TBSCertificate;
-import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLProvider;
/**
* This class is an implementation of X509Certificate. It wraps
@@ -372,7 +371,7 @@
Signature signature;
try {
- signature = OpenSSLSignature.getInstance(getSigAlgName());
+ signature = Signature.getInstance(getSigAlgName(), OpenSSLProvider.PROVIDER_NAME);
} catch (NoSuchAlgorithmException ignored) {
signature = Signature.getInstance(getSigAlgName());
}
@@ -393,7 +392,7 @@
Signature signature;
try {
if (sigProvider == null) {
- signature = OpenSSLSignature.getInstance(getSigAlgName());
+ signature = Signature.getInstance(getSigAlgName(), OpenSSLProvider.PROVIDER_NAME);
} else {
signature = Signature.getInstance(getSigAlgName(), sigProvider);
}
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index 70a13f7..f6efb8a 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -33,7 +33,6 @@
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.security.auth.x500.X500Principal;
@@ -43,7 +42,7 @@
import org.apache.harmony.security.pkcs7.SignerInfo;
import org.apache.harmony.security.provider.cert.X509CertImpl;
import org.apache.harmony.security.x501.AttributeTypeAndValue;
-import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLProvider;
public class JarUtils {
@@ -122,7 +121,7 @@
if (da != null && dea != null) {
alg = da + "with" + dea;
try {
- sig = OpenSSLSignature.getInstance(alg);
+ sig = Signature.getInstance(alg, OpenSSLProvider.PROVIDER_NAME);
} catch (NoSuchAlgorithmException e) {}
}
if (sig == null) {
@@ -131,7 +130,7 @@
return null;
}
try {
- sig = OpenSSLSignature.getInstance(alg);
+ sig = Signature.getInstance(alg, OpenSSLProvider.PROVIDER_NAME);
} catch (NoSuchAlgorithmException e) {
return null;
}
diff --git a/luni/src/main/java/org/apache/harmony/security/x509/GeneralName.java b/luni/src/main/java/org/apache/harmony/security/x509/GeneralName.java
index d8188be..e216029 100644
--- a/luni/src/main/java/org/apache/harmony/security/x509/GeneralName.java
+++ b/luni/src/main/java/org/apache/harmony/security/x509/GeneralName.java
@@ -539,9 +539,12 @@
}
/**
- * Checks the correctness of the string representation of DNS name.
- * The correctness is checked as specified in RFC 1034 p. 10, and modified
- * by RFC 1123 (section 2.1).
+ * Checks the correctness of the string representation of DNS name as
+ * specified in RFC 1034 p. 10 and RFC 1123 section 2.1.
+ *
+ * <p>This permits a wildcard character '*' anywhere in the name; it is up
+ * to the application to check which wildcards are permitted. See RFC 6125
+ * for recommended wildcard matching rules.
*/
public static void checkDNS(String dns) throws IOException {
String string = dns.toLowerCase(Locale.US);
@@ -551,18 +554,14 @@
for (int i = 0; i < length; i++) {
char ch = string.charAt(i);
if (first_letter) {
- if ((length > 2) && (ch == '*') && (string.charAt(1) == '.')) {
- first_letter = false;
- continue;
- }
- if ((ch > 'z' || ch < 'a') && (ch < '0' || ch > '9')) {
+ if ((ch > 'z' || ch < 'a') && (ch < '0' || ch > '9') && (ch != '*')) {
throw new IOException("DNS name must start with a letter: " + dns);
}
first_letter = false;
continue;
}
if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
- || (ch == '-') || (ch == '.'))) {
+ || (ch == '-') || (ch == '.') || (ch == '*'))) {
throw new IOException("Incorrect DNS name: " + dns);
}
if (ch == '.') {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
index d21aa2c..4b29363 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
@@ -36,6 +36,7 @@
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
+import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
import javax.security.auth.x500.X500Principal;
@@ -416,10 +417,10 @@
try {
c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
if (serverKeyExchange != null) {
- c.init(Cipher.ENCRYPT_MODE, serverKeyExchange
+ c.init(Cipher.WRAP_MODE, serverKeyExchange
.getRSAPublicKey());
} else {
- c.init(Cipher.ENCRYPT_MODE, serverCert.certs[0]);
+ c.init(Cipher.WRAP_MODE, serverCert.certs[0]);
}
} catch (Exception e) {
fatalAlert(AlertProtocol.INTERNAL_ERROR,
@@ -431,7 +432,7 @@
System.arraycopy(clientHello.client_version, 0, preMasterSecret, 0, 2);
try {
clientKeyExchange = new ClientKeyExchange(c
- .doFinal(preMasterSecret),
+ .wrap(new SecretKeySpec(preMasterSecret, "preMasterSecret")),
serverHello.server_version[1] == 1);
} catch (Exception e) {
fatalAlert(AlertProtocol.INTERNAL_ERROR,
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 5e759c1..759fc85 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -26,7 +26,6 @@
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
-import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -48,15 +47,69 @@
private native static void clinit();
+ // --- ENGINE functions ----------------------------------------------------
+ public static native void ENGINE_load_dynamic();
+
+ public static native int ENGINE_by_id(String id);
+
+ public static native int ENGINE_init(int e);
+
+ public static native int ENGINE_finish(int e);
+
+ public static native int ENGINE_free(int e);
+
+ public static native int ENGINE_load_private_key(int e, String key_id);
+
// --- DSA/RSA public/private key handling functions -----------------------
public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
- byte[] priv_key, byte[] pub_key);
+ byte[] pub_key, byte[] priv_key);
- public static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
+ public static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q,
+ byte[] dmp1, byte[] dmq1, byte[] iqmp);
+
+ public static native int EVP_PKEY_size(int pkey);
+
+ public static native int EVP_PKEY_type(int pkey);
public static native void EVP_PKEY_free(int pkey);
+ public static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int pkey);
+
+ public static native int d2i_PKCS8_PRIV_KEY_INFO(byte[] data);
+
+ public static native byte[] i2d_PUBKEY(int pkey);
+
+ public static native int d2i_PUBKEY(byte[] data);
+
+ public static native int RSA_generate_key_ex(int modulusBits, byte[] publicExponent);
+
+ /**
+ * @return array of {n, e}
+ */
+ public static native byte[][] get_RSA_public_params(int rsa);
+
+ /**
+ * @return array of {n, e, d, p, q, dmp1, dmq1, iqmp}
+ */
+ public static native byte[][] get_RSA_private_params(int rsa);
+
+ public static native int DSA_generate_key(int primeBits, byte[] seed, byte[] g, byte[] p,
+ byte[] q);
+
+ /**
+ * @return array of {g, p, q, y(pub), x(priv)}
+ */
+ public static native byte[][] get_DSA_params(int dsa);
+
+ public static native byte[] i2d_RSAPublicKey(int rsa);
+
+ public static native byte[] i2d_RSAPrivateKey(int rsa);
+
+ public static native byte[] i2d_DSAPublicKey(int dsa);
+
+ public static native byte[] i2d_DSAPrivateKey(int dsa);
+
// --- Message digest functions --------------
public static native int EVP_get_digestbyname(String name);
@@ -81,6 +134,13 @@
// --- Signature handling functions ----------------------------------------
+ public static native int EVP_SignInit(String algorithm);
+
+ public static native void EVP_SignUpdate(int ctx, byte[] buffer,
+ int offset, int length);
+
+ public static native int EVP_SignFinal(int ctx, byte[] signature, int offset, int key);
+
public static native int EVP_VerifyInit(String algorithm);
public static native void EVP_VerifyUpdate(int ctx, byte[] buffer,
@@ -89,6 +149,21 @@
public static native int EVP_VerifyFinal(int ctx, byte[] signature,
int offset, int length, int key);
+
+ // --- Block ciphers -------------------------------------------------------
+
+ public static native int EVP_get_cipherbyname(String string);
+
+ public static native int EVP_CipherInit_ex(int cipherNid, byte[] key, byte[] iv,
+ boolean encrypting);
+
+ public static native int EVP_CipherUpdate(int ctx, byte[] out, int outOffset, byte[] in,
+ int inOffset);
+
+ public static native int EVP_CipherFinal_ex(int ctx, byte[] out, int outOffset);
+
+ public static native void EVP_CIPHER_CTX_cleanup(int ctx);
+
// --- RAND seeding --------------------------------------------------------
public static final int RAND_SEED_LENGTH_IN_BYTES = 1024;
@@ -118,6 +193,8 @@
private static final String SUPPORTED_PROTOCOL_SSLV3 = "SSLv3";
private static final String SUPPORTED_PROTOCOL_TLSV1 = "TLSv1";
+ private static final String SUPPORTED_PROTOCOL_TLSV1_1 = "TLSv1.1";
+ private static final String SUPPORTED_PROTOCOL_TLSV1_2 = "TLSv1.2";
public static final Map<String, String> OPENSSL_TO_STANDARD_CIPHER_SUITES
= new HashMap<String, String>();
@@ -250,14 +327,23 @@
SUPPORTED_CIPHER_SUITES[size] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
}
+ // EVP_PKEY types from evp.h and objects.h
+ public static final int EVP_PKEY_RSA = 6; // NID_rsaEcnryption
+ public static final int EVP_PKEY_DSA = 116; // NID_dsa
+ public static final int EVP_PKEY_DH = 28; // NID_dhKeyAgreement
+ public static final int EVP_PKEY_EC = 408; // NID_X9_62_id_ecPublicKey
+
// SSL mode from ssl.h
public static final long SSL_MODE_HANDSHAKE_CUTTHROUGH = 0x00000040L;
// SSL options from ssl.h
- public static final long SSL_OP_NO_TICKET = 0x00004000L;
- public static final long SSL_OP_NO_COMPRESSION = 0x00020000L;
- public static final long SSL_OP_NO_SSLv3 = 0x02000000L;
- public static final long SSL_OP_NO_TLSv1 = 0x04000000L;
+ public static final long SSL_OP_NO_TICKET = 0x00004000L;
+ public static final long SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000L;
+ public static final long SSL_OP_NO_COMPRESSION = 0x00020000L;
+ public static final long SSL_OP_NO_SSLv3 = 0x02000000L;
+ public static final long SSL_OP_NO_TLSv1 = 0x04000000L;
+ public static final long SSL_OP_NO_TLSv1_1 = 0x10000000L;
+ public static final long SSL_OP_NO_TLSv1_2 = 0x08000000L;
public static native int SSL_CTX_new();
@@ -307,6 +393,8 @@
public static native void SSL_CTX_free(int ssl_ctx);
+ public static native void SSL_CTX_set_session_id_context(int ssl_ctx, byte[] sid_ctx);
+
public static native int SSL_new(int ssl_ctx) throws SSLException;
public static byte[][] encodeCertificates(Certificate[] certificates)
@@ -320,6 +408,8 @@
public static native void SSL_use_certificate(int ssl, byte[][] asn1DerEncodedCertificateChain);
+ public static native void SSL_use_OpenSSL_PrivateKey(int ssl, int pkey);
+
public static native void SSL_use_PrivateKey(int ssl, byte[] pkcs8EncodedPrivateKey);
public static native void SSL_check_private_key(int ssl) throws SSLException;
@@ -347,8 +437,18 @@
public static native long SSL_clear_options(int ssl, long options);
+ public static String[] getDefaultProtocols() {
+ return new String[] { SUPPORTED_PROTOCOL_SSLV3,
+ SUPPORTED_PROTOCOL_TLSV1,
+ };
+ }
+
public static String[] getSupportedProtocols() {
- return new String[] { SUPPORTED_PROTOCOL_SSLV3, SUPPORTED_PROTOCOL_TLSV1 };
+ return new String[] { SUPPORTED_PROTOCOL_SSLV3,
+ SUPPORTED_PROTOCOL_TLSV1,
+ SUPPORTED_PROTOCOL_TLSV1_1,
+ SUPPORTED_PROTOCOL_TLSV1_2,
+ };
}
public static void setEnabledProtocols(int ssl, String[] protocols) {
@@ -356,7 +456,7 @@
// openssl uses negative logic letting you disable protocols.
// so first, assume we need to set all (disable all) and clear none (enable none).
// in the loop, selectively move bits from set to clear (from disable to enable)
- long optionsToSet = (SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
+ long optionsToSet = (SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
long optionsToClear = 0;
for (int i = 0; i < protocols.length; i++) {
String protocol = protocols[i];
@@ -366,6 +466,12 @@
} else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1)) {
optionsToSet &= ~SSL_OP_NO_TLSv1;
optionsToClear |= SSL_OP_NO_TLSv1;
+ } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1)) {
+ optionsToSet &= ~SSL_OP_NO_TLSv1_1;
+ optionsToClear |= SSL_OP_NO_TLSv1_1;
+ } else if (protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2)) {
+ optionsToSet &= ~SSL_OP_NO_TLSv1_2;
+ optionsToClear |= SSL_OP_NO_TLSv1_2;
} else {
// error checked by checkEnabledProtocols
throw new IllegalStateException();
@@ -386,7 +492,9 @@
throw new IllegalArgumentException("protocols[" + i + "] == null");
}
if ((!protocol.equals(SUPPORTED_PROTOCOL_SSLV3))
- && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1))) {
+ && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1))
+ && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1_1))
+ && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1_2))) {
throw new IllegalArgumentException("protocol " + protocol
+ " is not supported");
}
@@ -436,8 +544,8 @@
return cipherSuites;
}
- private static final String SUPPORTED_COMPRESSION_METHOD_ZLIB = "ZLIB";
- private static final String SUPPORTED_COMPRESSION_METHOD_NULL = "NULL";
+ public static final String SUPPORTED_COMPRESSION_METHOD_ZLIB = "ZLIB";
+ public static final String SUPPORTED_COMPRESSION_METHOD_NULL = "NULL";
private static final String[] SUPPORTED_COMPRESSION_METHODS
= { SUPPORTED_COMPRESSION_METHOD_ZLIB, SUPPORTED_COMPRESSION_METHOD_NULL };
@@ -516,15 +624,39 @@
public static native String SSL_get_servername(int sslNativePointer);
/**
+ * Enables NPN for all SSL connections in the context.
+ *
+ * <p>For clients this causes the NPN extension to be included in the
+ * ClientHello message.
+ *
+ * <p>For servers this causes the NPN extension to be included in the
+ * ServerHello message. The NPN extension will not be included in the
+ * ServerHello response if the client didn't include it in the ClientHello
+ * request.
+ *
+ * <p>In either case the caller should pass a non-null byte array of NPN
+ * protocols to {@link #SSL_do_handshake}.
+ */
+ public static native void SSL_CTX_enable_npn(int sslCtxNativePointer);
+
+ /**
+ * Disables NPN for all SSL connections in the context.
+ */
+ public static native void SSL_CTX_disable_npn(int sslCtxNativePointer);
+
+ /**
* Returns the sslSessionNativePointer of the negotiated session
*/
public static native int SSL_do_handshake(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
- int timeout,
- boolean client_mode)
+ int timeoutMillis,
+ boolean client_mode,
+ byte[] npnProtocols)
throws SSLException, SocketTimeoutException, CertificateException;
+ public static native byte[] SSL_get_npn_negotiated_protocol(int sslNativePointer);
+
/**
* Currently only intended for forcing renegotiation for testing.
* Not used within OpenSSLSocketImpl.
@@ -548,7 +680,7 @@
public static native int SSL_read(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
- byte[] b, int off, int len, int timeout)
+ byte[] b, int off, int len, int timeoutMillis)
throws IOException;
/**
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyFactory.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyFactory.java
new file mode 100644
index 0000000..e3f6ed5
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyFactory.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class OpenSSLDSAKeyFactory extends KeyFactorySpi {
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec instanceof DSAPublicKeySpec) {
+ DSAPublicKeySpec dsaKeySpec = (DSAPublicKeySpec) keySpec;
+
+ return new OpenSSLDSAPublicKey(dsaKeySpec);
+ } else if (keySpec instanceof X509EncodedKeySpec) {
+ X509EncodedKeySpec x509KeySpec = (X509EncodedKeySpec) keySpec;
+
+ try {
+ final OpenSSLKey key = new OpenSSLKey(
+ NativeCrypto.d2i_PUBKEY(x509KeySpec.getEncoded()));
+ return new OpenSSLDSAPublicKey(key);
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+ throw new InvalidKeySpecException("Must use DSAPublicKeySpec or X509EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec instanceof DSAPrivateKeySpec) {
+ DSAPrivateKeySpec dsaKeySpec = (DSAPrivateKeySpec) keySpec;
+
+ return new OpenSSLDSAPrivateKey(dsaKeySpec);
+ } else if (keySpec instanceof PKCS8EncodedKeySpec) {
+ PKCS8EncodedKeySpec pkcs8KeySpec = (PKCS8EncodedKeySpec) keySpec;
+
+ try {
+ final OpenSSLKey key = new OpenSSLKey(
+ NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(pkcs8KeySpec.getEncoded()));
+ return new OpenSSLDSAPrivateKey(key);
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+ throw new InvalidKeySpecException("Must use DSAPublicKeySpec or PKCS8EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ if (key == null) {
+ throw new InvalidKeySpecException("key == null");
+ }
+
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (key instanceof DSAPublicKey) {
+ DSAPublicKey dsaKey = (DSAPublicKey) key;
+
+ if (DSAPublicKeySpec.class.equals(keySpec)) {
+ BigInteger y = dsaKey.getY();
+
+ DSAParams params = dsaKey.getParams();
+ BigInteger p = params.getP();
+ BigInteger q = params.getQ();
+ BigInteger g = params.getG();
+
+ return (T) new DSAPublicKeySpec(y, p, q, g);
+ } else if (PKCS8EncodedKeySpec.class.equals(keySpec)) {
+ return (T) new PKCS8EncodedKeySpec(key.getEncoded());
+ } else {
+ throw new InvalidKeySpecException("Must be DSAPublicKeySpec or PKCS8EncodedKeySpec");
+ }
+ } else if (key instanceof DSAPrivateKey) {
+ DSAPrivateKey dsaKey = (DSAPrivateKey) key;
+
+ if (DSAPrivateKeySpec.class.equals(keySpec)) {
+ BigInteger x = dsaKey.getX();
+
+ DSAParams params = dsaKey.getParams();
+ BigInteger p = params.getP();
+ BigInteger q = params.getQ();
+ BigInteger g = params.getG();
+
+ return (T) new DSAPrivateKeySpec(x, p, q, g);
+ } else if (X509EncodedKeySpec.class.equals(keySpec)) {
+ return (T) new X509EncodedKeySpec(dsaKey.getEncoded());
+ } else {
+ throw new InvalidKeySpecException("Must be DSAPrivateKeySpec or X509EncodedKeySpec");
+ }
+ } else {
+ throw new InvalidKeySpecException("Must be DSAPublicKey or DSAPrivateKey");
+ }
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+
+ if (key instanceof DSAPublicKey) {
+ DSAPublicKey dsaKey = (DSAPublicKey) key;
+
+ BigInteger y = dsaKey.getY();
+
+ DSAParams params = dsaKey.getParams();
+ BigInteger p = params.getP();
+ BigInteger q = params.getQ();
+ BigInteger g = params.getG();
+
+ try {
+ return engineGeneratePublic(new DSAPublicKeySpec(y, p, q, g));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof DSAPrivateKey) {
+ DSAPrivateKey dsaKey = (DSAPrivateKey) key;
+
+ BigInteger x = dsaKey.getX();
+
+ DSAParams params = dsaKey.getParams();
+ BigInteger p = params.getP();
+ BigInteger q = params.getQ();
+ BigInteger g = params.getG();
+
+ try {
+ return engineGeneratePublic(new DSAPrivateKeySpec(x, p, q, g));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else {
+ throw new InvalidKeyException("Key is not DSAPublicKey or DSAPrivateKey");
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyPairGenerator.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyPairGenerator.java
new file mode 100644
index 0000000..aa0b317
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAKeyPairGenerator.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGeneratorSpi;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+public class OpenSSLDSAKeyPairGenerator extends KeyPairGeneratorSpi {
+
+ private int primeBits = 1024;
+
+ private SecureRandom random = null;
+
+ private byte[] g;
+
+ private byte[] p;
+
+ private byte[] q;
+
+ @Override
+ public KeyPair generateKeyPair() {
+ final byte[] seed;
+ if (random == null) {
+ seed = null;
+ } else {
+ seed = new byte[20];
+ random.nextBytes(seed);
+ }
+
+ final OpenSSLKey key = new OpenSSLKey(NativeCrypto.DSA_generate_key(primeBits, seed, g, p,
+ q));
+
+ final OpenSSLDSAPrivateKey privKey = new OpenSSLDSAPrivateKey(key);
+ final OpenSSLDSAPublicKey pubKey = new OpenSSLDSAPublicKey(key);
+
+ return new KeyPair(pubKey, privKey);
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ primeBits = keysize;
+ this.random = random;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ this.random = random;
+
+ if (params instanceof DSAParameterSpec) {
+ DSAParameterSpec dsaParams = (DSAParameterSpec) params;
+
+ BigInteger gInt = dsaParams.getG();
+ if (gInt != null) {
+ g = gInt.toByteArray();
+ }
+
+ BigInteger pInt = dsaParams.getP();
+ if (pInt != null) {
+ p = pInt.toByteArray();
+ }
+
+ BigInteger qInt = dsaParams.getQ();
+ if (qInt != null) {
+ q = qInt.toByteArray();
+ }
+ } else if (params != null) {
+ throw new InvalidAlgorithmParameterException("Params must be DSAParameterSpec");
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAParams.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAParams.java
new file mode 100644
index 0000000..08aebf0
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAParams.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.spec.AlgorithmParameterSpec;
+
+public class OpenSSLDSAParams implements DSAParams, AlgorithmParameterSpec {
+
+ private OpenSSLKey key;
+
+ private boolean fetchedParams;
+
+ private BigInteger g;
+
+ private BigInteger p;
+
+ private BigInteger q;
+
+ private BigInteger y;
+
+ private BigInteger x;
+
+ OpenSSLDSAParams(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ private synchronized final void ensureReadParams() {
+ if (fetchedParams) {
+ return;
+ }
+
+ byte[][] params = NativeCrypto.get_DSA_params(key.getPkeyContext());
+ g = new BigInteger(params[0]);
+ p = new BigInteger(params[1]);
+ q = new BigInteger(params[2]);
+ if (params[3] != null) {
+ y = new BigInteger(params[3]);
+ }
+ if (params[4] != null) {
+ x = new BigInteger(params[4]);
+ }
+
+ fetchedParams = true;
+ }
+
+ @Override
+ public BigInteger getG() {
+ ensureReadParams();
+ return g;
+ }
+
+ @Override
+ public BigInteger getP() {
+ ensureReadParams();
+ return p;
+ }
+
+ @Override
+ public BigInteger getQ() {
+ ensureReadParams();
+ return q;
+ }
+
+ BigInteger getY() {
+ ensureReadParams();
+ return y;
+ }
+
+ BigInteger getX() {
+ ensureReadParams();
+ return x;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLDSAParams) {
+ OpenSSLDSAParams other = (OpenSSLDSAParams) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key == other.getOpenSSLKey()) {
+ return true;
+ }
+ }
+
+ if (!(o instanceof DSAParams)) {
+ return false;
+ }
+
+ ensureReadParams();
+
+ DSAParams other = (DSAParams) o;
+ return g.equals(other.getG()) && p.equals(other.getP()) && q.equals(other.getQ());
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+
+ return g.hashCode() ^ p.hashCode() ^ q.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ ensureReadParams();
+
+ final StringBuilder sb = new StringBuilder("OpenSSLDSAParams{");
+ sb.append("G=");
+ sb.append(g.toString(16));
+ sb.append(",P=");
+ sb.append(p.toString(16));
+ sb.append(",Q=");
+ sb.append(q.toString(16));
+ sb.append('}');
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java
new file mode 100644
index 0000000..7cd16f7
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPrivateKey.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+public class OpenSSLDSAPrivateKey implements DSAPrivateKey {
+ private static final long serialVersionUID = 6524734576187424628L;
+
+ private final OpenSSLKey key;
+
+ private OpenSSLDSAParams params;
+
+ OpenSSLDSAPrivateKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ OpenSSLDSAPrivateKey(DSAPrivateKeySpec dsaKeySpec) throws InvalidKeySpecException {
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
+ dsaKeySpec.getP().toByteArray(),
+ dsaKeySpec.getQ().toByteArray(),
+ dsaKeySpec.getG().toByteArray(),
+ null,
+ dsaKeySpec.getX().toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ private void ensureReadParams() {
+ if (params == null) {
+ params = new OpenSSLDSAParams(key);
+ }
+ }
+
+ static OpenSSLKey getInstance(DSAPrivateKey dsaPrivateKey) throws InvalidKeyException {
+ try {
+ DSAParams dsaParams = dsaPrivateKey.getParams();
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
+ dsaParams.getP().toByteArray(),
+ dsaParams.getQ().toByteArray(),
+ dsaParams.getG().toByteArray(),
+ null,
+ dsaPrivateKey.getX().toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public DSAParams getParams() {
+ ensureReadParams();
+ return params;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "DSA";
+ }
+
+ @Override
+ public String getFormat() {
+ /*
+ * If we're using an OpenSSL ENGINE, there's no guarantee we can export
+ * the key. Returning {@code null} tells the caller that there's no
+ * encoded format.
+ */
+ if (key.isEngineBased()) {
+ return null;
+ }
+
+ return "PKCS#8";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ /*
+ * If we're using an OpenSSL ENGINE, there's no guarantee we can export
+ * the key. Returning {@code null} tells the caller that there's no
+ * encoded format.
+ */
+ if (key.isEngineBased()) {
+ return null;
+ }
+
+ return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext());
+ }
+
+ @Override
+ public BigInteger getX() {
+ ensureReadParams();
+ return params.getX();
+ }
+
+ public int getPkeyContext() {
+ return key.getPkeyContext();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLDSAPrivateKey) {
+ OpenSSLDSAPrivateKey other = (OpenSSLDSAPrivateKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key.equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (!(o instanceof DSAPrivateKey)) {
+ return false;
+ }
+
+ ensureReadParams();
+
+ final BigInteger x = params.getX();
+ if (x == null) {
+ /*
+ * If our X is null, we can't tell if these two private keys are
+ * equivalent. This usually happens if this key is ENGINE-based. If
+ * the other key was ENGINE-based, we should have caught it in the
+ * OpenSSLDSAPrivateKey case.
+ */
+ return false;
+ }
+
+ final DSAPrivateKey other = (DSAPrivateKey) o;
+ return x.equals(other.getX()) && params.equals(other.getParams());
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+
+ int hash = 1;
+
+ final BigInteger x = getX();
+ if (x != null) {
+ hash = hash * 3 + x.hashCode();
+ }
+
+ hash = hash * 7 + params.hashCode();
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("OpenSSLDSAPrivateKey{");
+
+ if (key.isEngineBased()) {
+ sb.append("key=");
+ sb.append(key);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ ensureReadParams();
+ sb.append("X=");
+ sb.append(params.getX().toString(16));
+ sb.append(',');
+ sb.append("params=");
+ sb.append(params.toString());
+ sb.append('}');
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPublicKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPublicKey.java
new file mode 100644
index 0000000..25869bb
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLDSAPublicKey.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+public class OpenSSLDSAPublicKey implements DSAPublicKey {
+ private static final long serialVersionUID = 5238609500353792232L;
+
+ private final OpenSSLKey key;
+
+ private OpenSSLDSAParams params;
+
+ OpenSSLDSAPublicKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ OpenSSLDSAPublicKey(DSAPublicKeySpec dsaKeySpec) throws InvalidKeySpecException {
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
+ dsaKeySpec.getP().toByteArray(),
+ dsaKeySpec.getQ().toByteArray(),
+ dsaKeySpec.getG().toByteArray(),
+ dsaKeySpec.getY().toByteArray(),
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ private void ensureReadParams() {
+ if (params == null) {
+ params = new OpenSSLDSAParams(key);
+ }
+ }
+
+ static OpenSSLKey getInstance(DSAPublicKey dsaPublicKey) throws InvalidKeyException {
+ try {
+ final DSAParams dsaParams = dsaPublicKey.getParams();
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
+ dsaParams.getP().toByteArray(),
+ dsaParams.getQ().toByteArray(),
+ dsaParams.getG().toByteArray(),
+ dsaPublicKey.getY().toByteArray(),
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public DSAParams getParams() {
+ ensureReadParams();
+ return params;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "DSA";
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return NativeCrypto.i2d_PUBKEY(key.getPkeyContext());
+ }
+
+ @Override
+ public BigInteger getY() {
+ ensureReadParams();
+ return params.getY();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLDSAPublicKey) {
+ OpenSSLDSAPublicKey other = (OpenSSLDSAPublicKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key.equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (!(o instanceof DSAPublicKey)) {
+ return false;
+ }
+
+ ensureReadParams();
+
+ DSAPublicKey other = (DSAPublicKey) o;
+ return params.getY().equals(other.getY()) && params.equals(other.getParams());
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+
+ return params.getY().hashCode() ^ params.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ ensureReadParams();
+
+ final StringBuilder sb = new StringBuilder("OpenSSLDSAPublicKey{");
+ sb.append("Y=");
+ sb.append(params.getY().toString(16));
+ sb.append(',');
+ sb.append("params=");
+ sb.append(params.toString());
+ sb.append('}');
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java
new file mode 100644
index 0000000..e91e6d8
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLEngine.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+
+public class OpenSSLEngine {
+ static {
+ NativeCrypto.ENGINE_load_dynamic();
+ }
+
+ /** The ENGINE's native handle. */
+ private final int ctx;
+
+ public static OpenSSLEngine getInstance(String engine) throws IllegalArgumentException {
+ if (engine == null) {
+ throw new NullPointerException("engine == null");
+ }
+
+ final int engineCtx = NativeCrypto.ENGINE_by_id(engine);
+
+ if (engineCtx == 0) {
+ throw new IllegalArgumentException("Unknown ENGINE id: " + engine);
+ }
+
+ return new OpenSSLEngine(engineCtx);
+ }
+
+ private OpenSSLEngine(int engineCtx) {
+ ctx = engineCtx;
+
+ if (NativeCrypto.ENGINE_init(engineCtx) == 0) {
+ throw new IllegalArgumentException("Could not initialize engine");
+ }
+ }
+
+ public PrivateKey getPrivateKeyById(String id) throws InvalidKeyException {
+ if (id == null) {
+ throw new NullPointerException("id == null");
+ }
+
+ final int keyRef = NativeCrypto.ENGINE_load_private_key(ctx, id);
+ if (keyRef == 0) {
+ return null;
+ }
+
+ final int keyType = NativeCrypto.EVP_PKEY_type(keyRef);
+ switch (keyType) {
+ case NativeCrypto.EVP_PKEY_RSA:
+ return OpenSSLRSAPrivateKey.getInstance(new OpenSSLKey(keyRef, this));
+ case NativeCrypto.EVP_PKEY_DSA:
+ return new OpenSSLDSAPrivateKey(new OpenSSLKey(keyRef, this));
+ default:
+ throw new InvalidKeyException("Unknown key type: " + keyType);
+ }
+ }
+
+ int getEngineContext() {
+ return ctx;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ NativeCrypto.ENGINE_finish(ctx);
+ NativeCrypto.ENGINE_free(ctx);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof OpenSSLEngine)) {
+ return false;
+ }
+
+ OpenSSLEngine other = (OpenSSLEngine) o;
+
+ return other.getEngineContext() == ctx;
+ }
+
+ @Override
+ public int hashCode() {
+ return ctx;
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java
new file mode 100644
index 0000000..90eb0e2
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLKey.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+class OpenSSLKey {
+ private final int ctx;
+
+ private final OpenSSLEngine engine;
+
+ OpenSSLKey(int ctx) {
+ this.ctx = ctx;
+ engine = null;
+ }
+
+ OpenSSLKey(int ctx, OpenSSLEngine engine) {
+ this.ctx = ctx;
+ this.engine = engine;
+ }
+
+ int getPkeyContext() {
+ return ctx;
+ }
+
+ OpenSSLEngine getEngine() {
+ return engine;
+ }
+
+ boolean isEngineBased() {
+ return engine != null;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (ctx != 0) {
+ NativeCrypto.EVP_PKEY_free(ctx);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof OpenSSLKey)) {
+ return false;
+ }
+
+ OpenSSLKey other = (OpenSSLKey) o;
+ if (ctx != other.getPkeyContext()) {
+ return false;
+ }
+
+ if (engine == null) {
+ return other.getEngine() == null;
+ } else {
+ return engine.equals(other.getEngine());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 17 + ctx;
+ hash = hash * 31 + (engine == null ? 0 : engine.getEngineContext());
+ return hash;
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
index 4c8ad3a..97753cf 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -19,16 +19,21 @@
import java.security.Provider;
public final class OpenSSLProvider extends Provider {
+ public static final String PROVIDER_NAME = "AndroidOpenSSL";
public OpenSSLProvider() {
- super("AndroidOpenSSL", 1.0, "Android's OpenSSL-backed security provider");
+ super(PROVIDER_NAME, 1.0, "Android's OpenSSL-backed security provider");
+ // SSL Contexts
put("SSLContext.SSL", OpenSSLContextImpl.class.getName());
put("SSLContext.SSLv3", OpenSSLContextImpl.class.getName());
put("SSLContext.TLS", OpenSSLContextImpl.class.getName());
put("SSLContext.TLSv1", OpenSSLContextImpl.class.getName());
+ put("SSLContext.TLSv1.1", OpenSSLContextImpl.class.getName());
+ put("SSLContext.TLSv1.2", OpenSSLContextImpl.class.getName());
put("SSLContext.Default", DefaultSSLContextImpl.class.getName());
+ // Message Digests
put("MessageDigest.SHA-1",
"org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA1");
put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
@@ -54,6 +59,54 @@
"org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$MD5");
put("Alg.Alias.MessageDigest.1.2.840.113549.2.5", "MD5");
- // TODO Flush out implementation of OpenSSLSignature so it can be registered here
+ // KeyPairGenerators
+ put("KeyPairGenerator.RSA", OpenSSLRSAKeyPairGenerator.class.getName());
+ put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA");
+
+ put("KeyPairGenerator.DSA", OpenSSLDSAKeyPairGenerator.class.getName());
+
+ // KeyFactory
+
+ put("KeyFactory.RSA", OpenSSLRSAKeyFactory.class.getName());
+ put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA");
+
+ // put("KeyFactory.DSA", OpenSSLDSAKeyFactory.class.getName());
+
+ // Signatures
+ put("Signature.MD5WithRSAEncryption", OpenSSLSignature.MD5RSA.class.getName());
+ put("Alg.Alias.Signature.MD5WithRSA", "MD5WithRSAEncryption");
+ put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1",
+ "MD5WithRSAEncryption");
+
+ put("Signature.SHA1WithRSAEncryption", OpenSSLSignature.SHA1RSA.class.getName());
+ put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
+ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSAEncryption");
+
+ put("Signature.SHA256WithRSAEncryption", OpenSSLSignature.SHA256RSA.class.getName());
+ put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSAEncryption");
+
+ put("Signature.SHA384WithRSAEncryption", OpenSSLSignature.SHA384RSA.class.getName());
+ put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSAEncryption");
+
+ put("Signature.SHA512WithRSAEncryption", OpenSSLSignature.SHA512RSA.class.getName());
+ put("Alg.Alias.Signature.SHA512WithRSA", "SHA512WithRSAEncryption");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSAEncryption");
+
+ put("Signature.SHA1withDSA", OpenSSLSignature.SHA1DSA.class.getName());
+ put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
+ put("Alg.Alias.Signature.DSA", "SHA1withDSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
+ put("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA");
+ put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA");
}
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java
new file mode 100644
index 0000000..49d31d3
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyFactory.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class OpenSSLRSAKeyFactory<T, S> extends KeyFactorySpi {
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec instanceof RSAPublicKeySpec) {
+ RSAPublicKeySpec rsaKeySpec = (RSAPublicKeySpec) keySpec;
+
+ return new OpenSSLRSAPublicKey(rsaKeySpec);
+ } else if (keySpec instanceof X509EncodedKeySpec) {
+ X509EncodedKeySpec x509KeySpec = (X509EncodedKeySpec) keySpec;
+
+ try {
+ final OpenSSLKey key = new OpenSSLKey(
+ NativeCrypto.d2i_PUBKEY(x509KeySpec.getEncoded()));
+ return new OpenSSLRSAPublicKey(key);
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+ throw new InvalidKeySpecException("Must use RSAPublicKeySpec or X509EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ if (keySpec instanceof RSAPrivateCrtKeySpec) {
+ RSAPrivateCrtKeySpec rsaKeySpec = (RSAPrivateCrtKeySpec) keySpec;
+
+ return new OpenSSLRSAPrivateCrtKey(rsaKeySpec);
+ } else if (keySpec instanceof RSAPrivateKeySpec) {
+ RSAPrivateKeySpec rsaKeySpec = (RSAPrivateKeySpec) keySpec;
+
+ return new OpenSSLRSAPrivateKey(rsaKeySpec);
+ } else if (keySpec instanceof PKCS8EncodedKeySpec) {
+ PKCS8EncodedKeySpec pkcs8KeySpec = (PKCS8EncodedKeySpec) keySpec;
+
+ try {
+ final OpenSSLKey key = new OpenSSLKey(
+ NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(pkcs8KeySpec.getEncoded()));
+ return OpenSSLRSAPrivateKey.getInstance(key);
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+ throw new InvalidKeySpecException("Must use RSAPublicKeySpec or PKCS8EncodedKeySpec; was "
+ + keySpec.getClass().getName());
+ }
+
+ @Override
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ if (key == null) {
+ throw new InvalidKeySpecException("key == null");
+ }
+
+ if (keySpec == null) {
+ throw new InvalidKeySpecException("keySpec == null");
+ }
+
+ if (key instanceof RSAPublicKey) {
+ RSAPublicKey rsaKey = (RSAPublicKey) key;
+
+ if (RSAPublicKeySpec.class.equals(keySpec)) {
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger publicExponent = rsaKey.getPublicExponent();
+ return (T) new RSAPublicKeySpec(modulus, publicExponent);
+ } else if (X509EncodedKeySpec.class.equals(keySpec)) {
+ return (T) new X509EncodedKeySpec(key.getEncoded());
+ } else {
+ throw new InvalidKeySpecException("Must be RSAPublicKeySpec or X509EncodedKeySpec");
+ }
+ } else if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+
+ if (RSAPrivateKeySpec.class.equals(keySpec)) {
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ return (T) new RSAPrivateKeySpec(modulus, privateExponent);
+ } else if (RSAPrivateCrtKeySpec.class.equals(keySpec)) {
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger publicExponent = rsaKey.getPublicExponent();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ BigInteger primeP = rsaKey.getPrimeP();
+ BigInteger primeQ = rsaKey.getPrimeQ();
+ BigInteger primeExponentP = rsaKey.getPrimeExponentP();
+ BigInteger primeExponentQ = rsaKey.getPrimeExponentQ();
+ BigInteger crtCoefficient = rsaKey.getCrtCoefficient();
+ return (T) new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent,
+ primeP, primeQ, primeExponentP, primeExponentQ, crtCoefficient);
+ } else if (PKCS8EncodedKeySpec.class.equals(keySpec)) {
+ return (T) new PKCS8EncodedKeySpec(rsaKey.getEncoded());
+ } else {
+ throw new InvalidKeySpecException(
+ "Must be RSAPrivateKeySpec or or RSAPrivateCrtKeySpec or PKCS8EncodedKeySpec");
+ }
+ } else if (key instanceof RSAPrivateKey) {
+ RSAPrivateKey rsaKey = (RSAPrivateKey) key;
+
+ if (RSAPrivateKeySpec.class.equals(keySpec)) {
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ return (T) new RSAPrivateKeySpec(modulus, privateExponent);
+ } else if (RSAPrivateCrtKeySpec.class.equals(keySpec)) {
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ return (T) new RSAPrivateCrtKeySpec(modulus, null, privateExponent, null, null,
+ null, null, null);
+ } else if (PKCS8EncodedKeySpec.class.equals(keySpec)) {
+ return (T) new PKCS8EncodedKeySpec(rsaKey.getEncoded());
+ } else {
+ throw new InvalidKeySpecException(
+ "Must be RSAPrivateKeySpec or PKCS8EncodedKeySpec");
+ }
+ } else {
+ throw new InvalidKeySpecException("Must be RSAPublicKey or RSAPrivateKey");
+ }
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ }
+
+ if (key instanceof RSAPublicKey) {
+ RSAPublicKey rsaKey = (RSAPublicKey) key;
+
+ try {
+ return engineGeneratePublic(new RSAPublicKeySpec(rsaKey.getModulus(),
+ rsaKey.getPublicExponent()));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger publicExponent = rsaKey.getPublicExponent();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+ BigInteger primeP = rsaKey.getPrimeP();
+ BigInteger primeQ = rsaKey.getPrimeQ();
+ BigInteger primeExponentP = rsaKey.getPrimeExponentP();
+ BigInteger primeExponentQ = rsaKey.getPrimeExponentQ();
+ BigInteger crtCoefficient = rsaKey.getCrtCoefficient();
+
+ try {
+ return engineGeneratePrivate(new RSAPrivateCrtKeySpec(modulus, publicExponent,
+ privateExponent, primeP, primeQ, primeExponentP, primeExponentQ,
+ crtCoefficient));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else if (key instanceof RSAPrivateKey) {
+ RSAPrivateKey rsaKey = (RSAPrivateKey) key;
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger privateExponent = rsaKey.getPrivateExponent();
+
+ try {
+ return engineGeneratePrivate(new RSAPrivateKeySpec(modulus, privateExponent));
+ } catch (InvalidKeySpecException e) {
+ throw new InvalidKeyException(e);
+ }
+ } else {
+ throw new InvalidKeyException(
+ "Key must be RSAPublicKey or RSAPrivateCrtKey or RSAPrivateKey");
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyPairGenerator.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyPairGenerator.java
new file mode 100644
index 0000000..2d19d4e
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAKeyPairGenerator.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGeneratorSpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+public class OpenSSLRSAKeyPairGenerator extends KeyPairGeneratorSpi {
+ /**
+ * Default modulus size is 0x10001 (65537)
+ */
+ private byte[] publicExponent = new byte[] {
+ 0x01, 0x00, 0x01
+ };
+
+ /**
+ * Default RSA key size 2048 bits.
+ */
+ private int modulusBits = 2048;
+
+ @Override
+ public KeyPair generateKeyPair() {
+ final OpenSSLKey key = new OpenSSLKey(NativeCrypto.RSA_generate_key_ex(modulusBits,
+ publicExponent));
+
+ PrivateKey privKey = OpenSSLRSAPrivateKey.getInstance(key);
+ PublicKey pubKey = new OpenSSLRSAPublicKey(key);
+
+ return new KeyPair(pubKey, privKey);
+ }
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ this.modulusBits = keysize;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+ if (!(params instanceof RSAKeyGenParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("Only RSAKeyGenParameterSpec supported");
+ }
+
+ RSAKeyGenParameterSpec spec = (RSAKeyGenParameterSpec) params;
+
+ final BigInteger publicExponent = spec.getPublicExponent();
+ if (publicExponent != null) {
+ this.publicExponent = publicExponent.toByteArray();
+ }
+
+ this.modulusBits = spec.getKeysize();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
new file mode 100644
index 0000000..8376515
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey {
+ private BigInteger publicExponent;
+
+ private BigInteger primeP;
+
+ private BigInteger primeQ;
+
+ private BigInteger primeExponentP;
+
+ private BigInteger primeExponentQ;
+
+ private BigInteger crtCoefficient;
+
+ OpenSSLRSAPrivateCrtKey(OpenSSLKey key) {
+ super(key);
+ }
+
+ OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) {
+ super(key, params);
+ }
+
+ public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ super(init(rsaKeySpec));
+ }
+
+ private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ BigInteger modulus = rsaKeySpec.getModulus();
+ BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeySpecException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeySpecException("privateExponent == null");
+ }
+
+ try {
+ /*
+ * OpenSSL uses the public modulus to do RSA blinding. If
+ * the public modulus is not available, the call to
+ * EVP_PKEY_new_RSA will turn off blinding for this key
+ * instance.
+ */
+ final BigInteger publicExponent = rsaKeySpec.getPublicExponent();
+ final BigInteger primeP = rsaKeySpec.getPrimeP();
+ final BigInteger primeQ = rsaKeySpec.getPrimeQ();
+ final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP();
+ final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ();
+ final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient();
+
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent == null ? null : publicExponent.toByteArray(),
+ privateExponent.toByteArray(),
+ primeP == null ? null : primeP.toByteArray(),
+ primeQ == null ? null : primeQ.toByteArray(),
+ primeExponentP == null ? null : primeExponentP.toByteArray(),
+ primeExponentQ == null ? null : primeExponentQ.toByteArray(),
+ crtCoefficient == null ? null : crtCoefficient.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException {
+ BigInteger modulus = rsaPrivateKey.getModulus();
+ BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeyException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeyException("privateExponent == null");
+ }
+
+ try {
+ /*
+ * OpenSSL uses the public modulus to do RSA blinding. If
+ * the public modulus is not available, the call to
+ * EVP_PKEY_new_RSA will turn off blinding for this key
+ * instance.
+ */
+ final BigInteger publicExponent = rsaPrivateKey.getPublicExponent();
+ final BigInteger primeP = rsaPrivateKey.getPrimeP();
+ final BigInteger primeQ = rsaPrivateKey.getPrimeQ();
+ final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP();
+ final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ();
+ final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient();
+
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ publicExponent == null ? null : publicExponent.toByteArray(),
+ privateExponent.toByteArray(),
+ primeP == null ? null : primeP.toByteArray(),
+ primeQ == null ? null : primeQ.toByteArray(),
+ primeExponentP == null ? null : primeExponentP.toByteArray(),
+ primeExponentQ == null ? null : primeExponentQ.toByteArray(),
+ crtCoefficient == null ? null : crtCoefficient.toByteArray()));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ synchronized void readParams(byte[][] params) {
+ super.readParams(params);
+ // params[0] read in super.readParams
+ if (params[1] != null) {
+ publicExponent = new BigInteger(params[1]);
+ }
+ // params[2] read in super.readParams
+ if (params[3] != null) {
+ primeP = new BigInteger(params[3]);
+ }
+ if (params[4] != null) {
+ primeQ = new BigInteger(params[4]);
+ }
+ if (params[5] != null) {
+ primeExponentP = new BigInteger(params[5]);
+ }
+ if (params[6] != null) {
+ primeExponentQ = new BigInteger(params[6]);
+ }
+ if (params[7] != null) {
+ crtCoefficient = new BigInteger(params[7]);
+ }
+ }
+
+ @Override
+ public BigInteger getPublicExponent() {
+ ensureReadParams();
+ return publicExponent;
+ }
+
+ @Override
+ public BigInteger getPrimeP() {
+ ensureReadParams();
+ return primeP;
+ }
+
+ @Override
+ public BigInteger getPrimeQ() {
+ ensureReadParams();
+ return primeQ;
+ }
+
+ @Override
+ public BigInteger getPrimeExponentP() {
+ ensureReadParams();
+ return primeExponentP;
+ }
+
+ @Override
+ public BigInteger getPrimeExponentQ() {
+ ensureReadParams();
+ return primeExponentQ;
+ }
+
+ @Override
+ public BigInteger getCrtCoefficient() {
+ ensureReadParams();
+ return crtCoefficient;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPrivateCrtKey) {
+ OpenSSLRSAPrivateCrtKey other = (OpenSSLRSAPrivateCrtKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (getOpenSSLKey().equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (o instanceof RSAPrivateCrtKey) {
+ ensureReadParams();
+ RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
+
+ return getModulus().equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent())
+ && getPrivateExponent().equals(other.getPrivateExponent())
+ && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
+ && primeExponentP.equals(other.getPrimeExponentP())
+ && primeExponentQ.equals(other.getPrimeExponentQ())
+ && crtCoefficient.equals(other.getCrtCoefficient());
+ }
+
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ int hashCode = super.hashCode();
+ if (publicExponent != null) {
+ hashCode ^= publicExponent.hashCode();
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{");
+
+ if (getOpenSSLKey().isEngineBased()) {
+ sb.append("key=");
+ sb.append(getOpenSSLKey());
+ sb.append('}');
+ return sb.toString();
+ }
+
+ ensureReadParams();
+ sb.append("modulus=");
+ sb.append(getModulus().toString(16));
+ sb.append(',');
+
+ if (publicExponent != null) {
+ sb.append("publicExponent=");
+ sb.append(publicExponent.toString(16));
+ sb.append(',');
+ }
+
+ sb.append("privateExponent=");
+ sb.append(getPrivateExponent().toString(16));
+ sb.append(',');
+
+ if (primeP != null) {
+ sb.append("primeP=");
+ sb.append(primeP.toString(16));
+ sb.append(',');
+ }
+
+ if (primeQ != null) {
+ sb.append("primeQ=");
+ sb.append(primeQ.toString(16));
+ sb.append(',');
+ }
+
+ if (primeExponentP != null) {
+ sb.append("primeExponentP=");
+ sb.append(primeExponentP.toString(16));
+ sb.append(',');
+ }
+
+ if (primeExponentQ != null) {
+ sb.append("primeExponentQ=");
+ sb.append(primeExponentQ.toString(16));
+ sb.append(',');
+ }
+
+ if (crtCoefficient != null) {
+ sb.append("crtCoefficient=");
+ sb.append(crtCoefficient.toString(16));
+ sb.append(',');
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
new file mode 100644
index 0000000..c9fa178
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateKeySpec;
+
+public class OpenSSLRSAPrivateKey implements RSAPrivateKey {
+ private static final long serialVersionUID = 4872170254439578735L;
+
+ private final OpenSSLKey key;
+
+ private boolean fetchedParams;
+
+ private BigInteger modulus;
+
+ private BigInteger privateExponent;
+
+ OpenSSLRSAPrivateKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLRSAPrivateKey(OpenSSLKey key, byte[][] params) {
+ this(key);
+ readParams(params);
+ fetchedParams = true;
+ }
+
+ final OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ public OpenSSLRSAPrivateKey(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ this(init(rsaKeySpec));
+ }
+
+ private static OpenSSLKey init(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
+ final BigInteger modulus = rsaKeySpec.getModulus();
+ final BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeySpecException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeySpecException("privateExponent == null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ null,
+ privateExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLRSAPrivateKey getInstance(OpenSSLKey key) {
+ byte[][] params = NativeCrypto.get_RSA_private_params(key.getPkeyContext());
+ if (params[1] != null) {
+ return new OpenSSLRSAPrivateCrtKey(key, params);
+ }
+ return new OpenSSLRSAPrivateKey(key, params);
+ }
+
+ static OpenSSLKey getInstance(RSAPrivateKey rsaPrivateKey) throws InvalidKeyException {
+ final BigInteger modulus = rsaPrivateKey.getModulus();
+ final BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
+
+ if (modulus == null) {
+ throw new InvalidKeyException("modulus == null");
+ } else if (privateExponent == null) {
+ throw new InvalidKeyException("privateExponent == null");
+ }
+
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ modulus.toByteArray(),
+ null,
+ privateExponent.toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ synchronized final void ensureReadParams() {
+ if (fetchedParams) {
+ return;
+ }
+ readParams(NativeCrypto.get_RSA_private_params(key.getPkeyContext()));
+ fetchedParams = true;
+ }
+
+ void readParams(byte[][] params) {
+ if (params[0] == null) {
+ throw new NullPointerException("modulus == null");
+ } else if (params[2] == null && !key.isEngineBased()) {
+ throw new NullPointerException("privateExponent == null");
+ }
+
+ modulus = new BigInteger(params[0]);
+
+ // ENGINE-based keys are not guaranteed to have a private exponent.
+ if (params[2] != null) {
+ privateExponent = new BigInteger(params[2]);
+ }
+ }
+
+ @Override
+ public final BigInteger getPrivateExponent() {
+ ensureReadParams();
+ return privateExponent;
+ }
+
+ @Override
+ public final BigInteger getModulus() {
+ ensureReadParams();
+ return modulus;
+ }
+
+ @Override
+ public final byte[] getEncoded() {
+ /*
+ * If we're using an OpenSSL ENGINE, there's no guarantee we can export
+ * the key. Returning {@code null} tells the caller that there's no
+ * encoded format.
+ */
+ if (key.isEngineBased()) {
+ return null;
+ }
+
+ return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext());
+ }
+
+ public final String getFormat() {
+ /*
+ * If we're using an OpenSSL ENGINE, there's no guarantee we can export
+ * the key. Returning {@code null} tells the caller that there's no
+ * encoded format.
+ */
+ if (key.isEngineBased()) {
+ return null;
+ }
+
+ return "PKCS#8";
+ }
+
+ @Override
+ public final String getAlgorithm() {
+ return "RSA";
+ }
+
+ public int getPkeyContext() {
+ return key.getPkeyContext();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key.equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (o instanceof RSAPrivateKey) {
+ ensureReadParams();
+ RSAPrivateKey other = (RSAPrivateKey) o;
+
+ return modulus.equals(other.getModulus())
+ && privateExponent.equals(other.getPrivateExponent());
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+ int hash = 1;
+
+ hash = hash * 3 + modulus.hashCode();
+ if (privateExponent != null) {
+ hash = hash * 7 + privateExponent.hashCode();
+ }
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{");
+
+ if (key.isEngineBased()) {
+ sb.append("key=");
+ sb.append(key);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ ensureReadParams();
+ sb.append("modulus=");
+ sb.append(modulus.toString(16));
+ sb.append(',');
+
+ sb.append("privateExponent=");
+ sb.append(privateExponent.toString(16));
+ sb.append(',');
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPublicKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPublicKey.java
new file mode 100644
index 0000000..1613cf0
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPublicKey.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+
+public class OpenSSLRSAPublicKey implements RSAPublicKey {
+ private static final long serialVersionUID = 123125005824688292L;
+
+ private final OpenSSLKey key;
+
+ private BigInteger publicExponent;
+
+ private BigInteger modulus;
+
+ private boolean fetchedParams;
+
+ OpenSSLRSAPublicKey(OpenSSLKey key) {
+ this.key = key;
+ }
+
+ OpenSSLKey getOpenSSLKey() {
+ return key;
+ }
+
+ OpenSSLRSAPublicKey(RSAPublicKeySpec spec) throws InvalidKeySpecException {
+ try {
+ key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ spec.getModulus().toByteArray(),
+ spec.getPublicExponent().toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ static OpenSSLKey getInstance(RSAPublicKey rsaPublicKey) throws InvalidKeyException {
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
+ rsaPublicKey.getModulus().toByteArray(),
+ rsaPublicKey.getPublicExponent().toByteArray(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null));
+ } catch (Exception e) {
+ throw new InvalidKeyException(e);
+ }
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "RSA";
+ }
+
+ @Override
+ public String getFormat() {
+ return "X.509";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return NativeCrypto.i2d_PUBKEY(key.getPkeyContext());
+ }
+
+ private void ensureReadParams() {
+ if (fetchedParams) {
+ return;
+ }
+
+ byte[][] params = NativeCrypto.get_RSA_public_params(key.getPkeyContext());
+ modulus = new BigInteger(params[0]);
+ publicExponent = new BigInteger(params[1]);
+
+ fetchedParams = true;
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ ensureReadParams();
+ return modulus;
+ }
+
+ @Override
+ public BigInteger getPublicExponent() {
+ ensureReadParams();
+ return publicExponent;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o instanceof OpenSSLRSAPublicKey) {
+ OpenSSLRSAPublicKey other = (OpenSSLRSAPublicKey) o;
+
+ /*
+ * We can shortcut the true case, but it still may be equivalent but
+ * different copies.
+ */
+ if (key.equals(other.getOpenSSLKey())) {
+ return true;
+ }
+ }
+
+ if (!(o instanceof RSAPublicKey)) {
+ return false;
+ }
+
+ ensureReadParams();
+
+ RSAPublicKey other = (RSAPublicKey) o;
+ return modulus.equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent());
+ }
+
+ @Override
+ public int hashCode() {
+ ensureReadParams();
+
+ return modulus.hashCode() ^ publicExponent.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ ensureReadParams();
+
+ final StringBuilder sb = new StringBuilder("OpenSSLRSAPublicKey{");
+ sb.append("modulus=");
+ sb.append(modulus.toString(16));
+ sb.append(',');
+ sb.append("publicExponent=");
+ sb.append(publicExponent.toString(16));
+ sb.append('}');
+
+ return sb.toString();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
index 20219e0..841c31c 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java
@@ -27,9 +27,6 @@
/**
* OpenSSL-based implementation of server sockets.
- *
- * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
- * later, for example in the package.html or a separate reference document.
*/
public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket {
private final SSLParametersImpl sslParameters;
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
index bcccda7..370e7a4 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignature.java
@@ -23,66 +23,20 @@
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
-import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
/**
* Implements the subset of the JDK Signature interface needed for
* signature verification using OpenSSL.
*/
public class OpenSSLSignature extends Signature {
-
- private static Map<String,Class<? extends OpenSSLSignature>> jdkToOpenSsl
- = new HashMap<String,Class<? extends OpenSSLSignature>>();
- private static void register(String algorithm, Class implementation) {
- jdkToOpenSsl.put(algorithm.toUpperCase(Locale.US), implementation);
- }
- private static Class lookup(String algorithm) {
- return jdkToOpenSsl.get(algorithm.toUpperCase(Locale.US));
- }
-
- static {
- // TODO Finish OpenSSLSignature implementation and move
- // registration information to the OpenSSLProvider
- register("MD5WithRSAEncryption", MD5RSA.class);
- register("MD5WithRSA", MD5RSA.class);
- register("MD5/RSA", MD5RSA.class);
- register("1.2.840.113549.1.1.4", MD5RSA.class);
- register("1.2.840.113549.2.5with1.2.840.113549.1.1.1", MD5RSA.class);
-
- register("SHA1WithRSAEncryption", SHA1RSA.class);
- register("SHA1WithRSA", SHA1RSA.class);
- register("SHA1/RSA", SHA1RSA.class);
- register("SHA-1/RSA", SHA1RSA.class);
- register("1.2.840.113549.1.1.5", SHA1RSA.class);
- register("1.3.14.3.2.26with1.2.840.113549.1.1.1", SHA1RSA.class);
- register("1.3.14.3.2.26with1.2.840.113549.1.1.5", SHA1RSA.class);
- register("1.3.14.3.2.29", SHA1RSA.class);
-
- register("SHA256WithRSAEncryption", SHA256RSA.class);
- register("SHA256WithRSA", SHA256RSA.class);
- register("1.2.840.113549.1.1.11", SHA256RSA.class);
-
- register("SHA384WithRSAEncryption", SHA384RSA.class);
- register("SHA384WithRSA", SHA384RSA.class);
- register("1.2.840.113549.1.1.12", SHA384RSA.class);
-
- register("SHA512WithRSAEncryption", SHA512RSA.class);
- register("SHA512WithRSA", SHA512RSA.class);
- register("1.2.840.113549.1.1.13", SHA512RSA.class);
-
- register("SHA1withDSA", SHA1DSA.class);
- register("SHA/DSA", SHA1DSA.class);
- register("DSA", SHA1DSA.class);
- register("1.3.14.3.2.26with1.2.840.10040.4.1", SHA1DSA.class);
- register("1.3.14.3.2.26with1.2.840.10040.4.3", SHA1DSA.class);
- register("DSAWithSHA1", SHA1DSA.class);
- register("1.2.840.10040.4.3", SHA1DSA.class);
- }
+ private static enum EngineType {
+ RSA, DSA,
+ };
/**
* Holds a pointer to the native message digest context.
@@ -90,14 +44,14 @@
private int ctx;
/**
- * Holds a pointer to the native DSA key.
+ * The current OpenSSL key we're operating on.
*/
- private int dsa;
+ private OpenSSLKey key;
/**
- * Holds a pointer to the native RSA key.
+ * Holds the type of the Java algorithm.
*/
- private int rsa;
+ private final EngineType engineType;
/**
* Holds the OpenSSL name of the algorithm (lower case, no dashes).
@@ -112,34 +66,10 @@
/**
* Creates a new OpenSSLSignature instance for the given algorithm name.
*
- * @param algorithm The name of the algorithm, e.g. "SHA1WithRSA".
- *
- * @return The new OpenSSLSignature instance.
- *
- * @throws RuntimeException In case of problems.
- */
- public static OpenSSLSignature getInstance(String algorithm) throws NoSuchAlgorithmException {
- // System.out.println("getInstance() invoked with " + algorithm);
-
- Class <? extends OpenSSLSignature> clazz = lookup(algorithm);
- if (clazz == null) {
- throw new NoSuchAlgorithmException(algorithm);
- }
- try {
- return clazz.newInstance();
- } catch (InstantiationException e) {
- throw new NoSuchAlgorithmException(algorithm, e);
- } catch (IllegalAccessException e) {
- throw new NoSuchAlgorithmException(algorithm, e);
- }
- }
-
- /**
- * Creates a new OpenSSLSignature instance for the given algorithm name.
- *
* @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1".
*/
- private OpenSSLSignature(String algorithm) throws NoSuchAlgorithmException {
+ private OpenSSLSignature(String algorithm, EngineType engineType)
+ throws NoSuchAlgorithmException {
super(algorithm);
// We don't support MD2
@@ -147,6 +77,7 @@
throw new NoSuchAlgorithmException(algorithm);
}
+ this.engineType = engineType;
this.evpAlgorithm = algorithm;
}
@@ -159,8 +90,24 @@
@Override
protected void engineUpdate(byte[] input, int offset, int len) {
if (state == SIGN) {
- throw new UnsupportedOperationException();
+ if (ctx == 0) {
+ try {
+ ctx = NativeCrypto.EVP_SignInit(evpAlgorithm);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ NativeCrypto.EVP_SignUpdate(ctx, input, offset, len);
} else {
+ if (ctx == 0) {
+ try {
+ ctx = NativeCrypto.EVP_VerifyInit(evpAlgorithm);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len);
}
}
@@ -172,43 +119,84 @@
@Override
protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
- throw new UnsupportedOperationException();
+ destroyContextIfExists();
+
+ if (privateKey instanceof OpenSSLDSAPrivateKey) {
+ if (engineType != EngineType.DSA) {
+ throw new InvalidKeyException("Signature not initialized as DSA");
+ }
+
+ OpenSSLDSAPrivateKey dsaPrivateKey = (OpenSSLDSAPrivateKey) privateKey;
+ key = dsaPrivateKey.getOpenSSLKey();
+ } else if (privateKey instanceof DSAPrivateKey) {
+ if (engineType != EngineType.DSA) {
+ throw new InvalidKeyException("Signature not initialized as DSA");
+ }
+
+ DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey;
+ key = OpenSSLDSAPrivateKey.getInstance(dsaPrivateKey);
+ } else if (privateKey instanceof OpenSSLRSAPrivateKey) {
+ if (engineType != EngineType.RSA) {
+ throw new InvalidKeyException("Signature not initialized as RSA");
+ }
+
+ OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey;
+ key = rsaPrivateKey.getOpenSSLKey();
+ } else if (privateKey instanceof RSAPrivateCrtKey) {
+ if (engineType != EngineType.RSA) {
+ throw new InvalidKeyException("Signature not initialized as RSA");
+ }
+
+ RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
+ key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey);
+ } else if (privateKey instanceof RSAPrivateKey) {
+ if (engineType != EngineType.RSA) {
+ throw new InvalidKeyException("Signature not initialized as RSA");
+ }
+
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
+ key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey);
+ } else {
+ throw new InvalidKeyException("Need DSA or RSA private key");
+ }
}
@Override
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
- // System.out.println("engineInitVerify() invoked with "
- // + publicKey.getClass().getCanonicalName());
+ // If we had an existing context, destroy it first.
+ destroyContextIfExists();
- if (publicKey instanceof DSAPublicKey) {
- try {
- DSAPublicKey dsaPublicKey = (DSAPublicKey)publicKey;
- DSAParams dsaParams = dsaPublicKey.getParams();
- dsa = NativeCrypto.EVP_PKEY_new_DSA(dsaParams.getP().toByteArray(),
- dsaParams.getQ().toByteArray(), dsaParams.getG().toByteArray(),
- dsaPublicKey.getY().toByteArray(), null);
-
- } catch (Exception e) {
- throw new InvalidKeyException(e);
+ if (publicKey instanceof OpenSSLDSAPublicKey) {
+ if (engineType != EngineType.DSA) {
+ throw new InvalidKeyException("Signature not initialized as DSA");
}
+
+ OpenSSLDSAPublicKey dsaPublicKey = (OpenSSLDSAPublicKey) publicKey;
+ key = dsaPublicKey.getOpenSSLKey();
+ } else if (publicKey instanceof DSAPublicKey) {
+ if (engineType != EngineType.DSA) {
+ throw new InvalidKeyException("Signature not initialized as DSA");
+ }
+
+ DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey;
+ key = OpenSSLDSAPublicKey.getInstance(dsaPublicKey);
+ } else if (publicKey instanceof OpenSSLRSAPublicKey) {
+ if (engineType != EngineType.RSA) {
+ throw new InvalidKeyException("Signature not initialized as RSA");
+ }
+
+ OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey;
+ key = rsaPublicKey.getOpenSSLKey();
} else if (publicKey instanceof RSAPublicKey) {
- try {
- RSAPublicKey rsaPublicKey = (RSAPublicKey)publicKey;
- rsa = NativeCrypto.EVP_PKEY_new_RSA(rsaPublicKey.getModulus().toByteArray(),
- rsaPublicKey.getPublicExponent().toByteArray(), null, null, null);
-
- } catch (Exception e) {
- throw new InvalidKeyException(e);
+ if (engineType != EngineType.RSA) {
+ throw new InvalidKeyException("Signature not initialized as RSA");
}
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
+ key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey);
} else {
throw new InvalidKeyException("Need DSA or RSA public key");
}
-
- try {
- ctx = NativeCrypto.EVP_VerifyInit(evpAlgorithm);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
}
@Override
@@ -217,37 +205,62 @@
@Override
protected byte[] engineSign() throws SignatureException {
- throw new UnsupportedOperationException();
+ if (key == null) {
+ // This can't actually happen, but you never know...
+ throw new SignatureException("Need DSA or RSA private key");
+ }
+
+ try {
+ byte[] buffer = new byte[NativeCrypto.EVP_PKEY_size(key.getPkeyContext())];
+ int bytesWritten = NativeCrypto.EVP_SignFinal(ctx, buffer, 0, key.getPkeyContext());
+
+ byte[] signature = new byte[bytesWritten];
+ System.arraycopy(buffer, 0, signature, 0, bytesWritten);
+
+ return signature;
+ } catch (Exception ex) {
+ throw new SignatureException(ex);
+ } finally {
+ /*
+ * Java expects the digest context to be reset completely after sign
+ * calls.
+ */
+ destroyContextIfExists();
+ }
}
@Override
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
- int handle = (rsa != 0) ? rsa : dsa;
-
- if (handle == 0) {
+ if (key == null) {
// This can't actually happen, but you never know...
throw new SignatureException("Need DSA or RSA public key");
}
try {
- int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, handle);
+ int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length,
+ key.getPkeyContext());
return result == 1;
} catch (Exception ex) {
throw new SignatureException(ex);
+ } finally {
+ /*
+ * Java expects the digest context to be reset completely after
+ * verify calls.
+ */
+ destroyContextIfExists();
}
-
}
- @Override protected void finalize() throws Throwable {
+ private void destroyContextIfExists() {
+ if (ctx != 0) {
+ NativeCrypto.EVP_MD_CTX_destroy(ctx);
+ ctx = 0;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
try {
- if (dsa != 0) {
- NativeCrypto.EVP_PKEY_free(dsa);
- }
-
- if (rsa != 0) {
- NativeCrypto.EVP_PKEY_free(rsa);
- }
-
if (ctx != 0) {
NativeCrypto.EVP_MD_CTX_destroy(ctx);
}
@@ -258,32 +271,32 @@
public static final class MD5RSA extends OpenSSLSignature {
public MD5RSA() throws NoSuchAlgorithmException {
- super("RSA-MD5");
+ super("RSA-MD5", EngineType.RSA);
}
}
public static final class SHA1RSA extends OpenSSLSignature {
public SHA1RSA() throws NoSuchAlgorithmException {
- super("RSA-SHA1");
+ super("RSA-SHA1", EngineType.RSA);
}
}
public static final class SHA256RSA extends OpenSSLSignature {
public SHA256RSA() throws NoSuchAlgorithmException {
- super("RSA-SHA256");
+ super("RSA-SHA256", EngineType.RSA);
}
}
public static final class SHA384RSA extends OpenSSLSignature {
public SHA384RSA() throws NoSuchAlgorithmException {
- super("RSA-SHA384");
+ super("RSA-SHA384", EngineType.RSA);
}
}
public static final class SHA512RSA extends OpenSSLSignature {
public SHA512RSA() throws NoSuchAlgorithmException {
- super("RSA-SHA512");
+ super("RSA-SHA512", EngineType.RSA);
}
}
public static final class SHA1DSA extends OpenSSLSignature {
public SHA1DSA() throws NoSuchAlgorithmException {
- super("DSA-SHA1");
+ super("DSA-SHA1", EngineType.DSA);
}
}
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index d4681ae..4c92952 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -18,7 +18,6 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
-
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -49,9 +48,6 @@
/**
* Implementation of the class OpenSSLSocketImpl based on OpenSSL.
* <p>
- * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
- * later, for example in the package.html or a separate reference document.
- * <p>
* Extensions to SSLSocket include:
* <ul>
* <li>handshake timeout
@@ -71,6 +67,7 @@
private final Object readLock = new Object();
private final Object writeLock = new Object();
private SSLParametersImpl sslParameters;
+ private byte[] npnProtocols;
private String[] enabledProtocols;
private String[] enabledCipherSuites;
private String[] enabledCompressionMethods;
@@ -171,7 +168,7 @@
*/
private void init(SSLParametersImpl sslParameters) throws IOException {
init(sslParameters,
- NativeCrypto.getSupportedProtocols(),
+ NativeCrypto.getDefaultProtocols(),
NativeCrypto.getDefaultCipherSuites(),
NativeCrypto.getDefaultCompressionMethods());
}
@@ -194,14 +191,12 @@
* Gets the suitable session reference from the session cache container.
*/
private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
- if (super.getInetAddress() == null ||
- super.getInetAddress().getHostAddress() == null ||
- super.getInetAddress().getHostName() == null) {
+ String hostName = getPeerHostName();
+ int port = getPeerPort();
+ if (hostName == null) {
return null;
}
- OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(
- super.getInetAddress().getHostName(),
- super.getPort());
+ OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
if (session == null) {
return null;
}
@@ -231,32 +226,22 @@
}
String compressionMethod = session.getCompressionMethod();
- boolean compressionMethodFound = false;
- for (String enabledCompressionMethod : enabledCompressionMethods) {
- if (compressionMethod.equals(enabledCompressionMethod)) {
- compressionMethodFound = true;
- break;
+ if (!compressionMethod.equals(NativeCrypto.SUPPORTED_COMPRESSION_METHOD_NULL)) {
+ boolean compressionMethodFound = false;
+ for (String enabledCompressionMethod : enabledCompressionMethods) {
+ if (compressionMethod.equals(enabledCompressionMethod)) {
+ compressionMethodFound = true;
+ break;
+ }
}
- }
- if (!compressionMethodFound) {
- return null;
+ if (!compressionMethodFound) {
+ return null;
+ }
}
return session;
}
- /**
- * Starts a TLS/SSL handshake on this connection using some native methods
- * from the OpenSSL library. It can negotiate new encryption keys, change
- * cipher suites, or initiate a new session. The certificate chain is
- * verified if the correspondent property in java.Security is set. All
- * listeners are notified at the end of the TLS/SSL handshake.
- */
- @Override
- public void startHandshake() throws IOException {
- startHandshake(true);
- }
-
private void checkOpen() throws SocketException {
if (isClosed()) {
throw new SocketException("Socket is closed");
@@ -264,11 +249,13 @@
}
/**
- * Perform the handshake
- *
- * @param full If true, disable handshake cutthrough for a fully synchronous handshake
+ * Starts a TLS/SSL handshake on this connection using some native methods
+ * from the OpenSSL library. It can negotiate new encryption keys, change
+ * cipher suites, or initiate a new session. The certificate chain is
+ * verified if the correspondent property in java.Security is set. All
+ * listeners are notified at the end of the TLS/SSL handshake.
*/
- public synchronized void startHandshake(boolean full) throws IOException {
+ @Override public synchronized void startHandshake() throws IOException {
synchronized (handshakeLock) {
checkOpen();
if (!handshakeStarted) {
@@ -299,6 +286,10 @@
sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
guard.open("close");
+ if (npnProtocols != null) {
+ NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
+ }
+
// setup server certificates and private keys.
// clients will receive a call back to request certificates.
if (!client) {
@@ -393,12 +384,6 @@
}
}
- if (client && full) {
- // we want to do a full synchronous handshake, so turn off cutthrough
- NativeCrypto.SSL_clear_mode(sslNativePointer,
- NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
- }
-
// Temporarily use a different timeout for the handshake process
int savedTimeoutMilliseconds = getSoTimeout();
if (handshakeTimeoutMilliseconds >= 0) {
@@ -408,7 +393,7 @@
int sslSessionNativePointer;
try {
sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
- socket.getFileDescriptor$(), this, getSoTimeout(), client);
+ socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
} catch (CertificateException e) {
SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
wrapper.initCause(e);
@@ -428,17 +413,8 @@
= createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
X509Certificate[] peerCertificates
= createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
- if (wrappedHost == null) {
- sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
- localCertificates, peerCertificates,
- super.getInetAddress().getHostName(),
- super.getPort(), sessionContext);
- } else {
- sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
- localCertificates, peerCertificates,
- wrappedHost, wrappedPort,
- sessionContext);
- }
+ sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
+ peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
// if not, putSession later in handshakeCompleted() callback
if (handshakeCompleted) {
sessionContext.putSession(sslSession);
@@ -466,6 +442,21 @@
}
}
+ private String getPeerHostName() {
+ if (wrappedHost != null) {
+ return wrappedHost;
+ }
+ InetAddress inetAddress = super.getInetAddress();
+ if (inetAddress != null) {
+ return inetAddress.getHostName();
+ }
+ return null;
+ }
+
+ private int getPeerPort() {
+ return wrappedHost == null ? super.getPort() : wrappedPort;
+ }
+
/**
* Return a possibly null array of X509Certificates given the
* possibly null array of DER encoded bytes.
@@ -498,9 +489,22 @@
return;
}
- byte[] privateKeyBytes = privateKey.getEncoded();
+ if (privateKey instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey rsaKey = (OpenSSLRSAPrivateKey) privateKey;
+ OpenSSLKey key = rsaKey.getOpenSSLKey();
+ NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
+ } else if (privateKey instanceof OpenSSLDSAPrivateKey) {
+ OpenSSLDSAPrivateKey dsaKey = (OpenSSLDSAPrivateKey) privateKey;
+ OpenSSLKey key = dsaKey.getOpenSSLKey();
+ NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
+ } else if ("PKCS#8".equals(privateKey.getFormat())) {
+ byte[] privateKeyBytes = privateKey.getEncoded();
+ NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
+ } else {
+ throw new SSLException("Unsupported PrivateKey format: " + privateKey.getFormat());
+ }
+
byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
- NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
// checks the last installed private key and certificate,
@@ -636,11 +640,11 @@
*/
private class SSLInputStream extends InputStream {
SSLInputStream() throws IOException {
- /**
- /* Note: When startHandshake() throws an exception, no
+ /*
+ * Note: When startHandshake() throws an exception, no
* SSLInputStream object will be created.
*/
- OpenSSLSocketImpl.this.startHandshake(false);
+ OpenSSLSocketImpl.this.startHandshake();
}
/**
@@ -681,11 +685,11 @@
*/
private class SSLOutputStream extends OutputStream {
SSLOutputStream() throws IOException {
- /**
- /* Note: When startHandshake() throws an exception, no
+ /*
+ * Note: When startHandshake() throws an exception, no
* SSLOutputStream object will be created.
*/
- OpenSSLSocketImpl.this.startHandshake(false);
+ OpenSSLSocketImpl.this.startHandshake();
}
/**
@@ -720,7 +724,7 @@
@Override public SSLSession getSession() {
if (sslSession == null) {
try {
- startHandshake(true);
+ startHandshake();
} catch (IOException e) {
// return an invalid session with
// invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
@@ -997,4 +1001,28 @@
return socket.getFileDescriptor$();
}
}
+
+ /**
+ * Returns the protocol agreed upon by client and server, or null if no
+ * protocol was agreed upon.
+ */
+ public byte[] getNpnSelectedProtocol() {
+ return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
+ }
+
+ /**
+ * Sets the list of protocols this peer is interested in. If null no
+ * protocols will be used.
+ *
+ * @param npnProtocols a non-empty array of protocol names. From
+ * SSL_select_next_proto, "vector of 8-bit, length prefixed byte
+ * strings. The length byte itself is not included in the length. A byte
+ * string of length 0 is invalid. No byte string may be truncated.".
+ */
+ public void setNpnProtocols(byte[] npnProtocols) {
+ if (npnProtocols != null && npnProtocols.length == 0) {
+ throw new IllegalArgumentException("npnProtocols.length == 0");
+ }
+ this.npnProtocols = npnProtocols;
+ }
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParametersImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParametersImpl.java
index a17492f..287f9f3 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParametersImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParametersImpl.java
@@ -24,6 +24,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
+import java.util.Arrays;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
@@ -112,9 +113,6 @@
} else {
keyManager = findX509KeyManager(kms);
}
- if (keyManager == null) {
- throw new KeyManagementException("No X509KeyManager found");
- }
// initialize trustManager
if ((tms == null) || (tms.length == 0)) {
@@ -122,9 +120,6 @@
} else {
trustManager = findX509TrustManager(tms);
}
- if (trustManager == null) {
- throw new KeyManagementException("No X509TrustManager found");
- }
// initialize secure random
// BEGIN android-removed
// if (sr == null) {
@@ -354,7 +349,7 @@
}
}
- private static X509KeyManager getDefaultKeyManager() {
+ private static X509KeyManager getDefaultKeyManager() throws KeyManagementException {
X509KeyManager result = defaultKeyManager;
if (result == null) {
// single-check idiom
@@ -362,7 +357,7 @@
}
return result;
}
- private static X509KeyManager createDefaultKeyManager() {
+ private static X509KeyManager createDefaultKeyManager() throws KeyManagementException {
try {
String algorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
@@ -370,20 +365,20 @@
KeyManager[] kms = kmf.getKeyManagers();
return findX509KeyManager(kms);
} catch (NoSuchAlgorithmException e) {
- return null;
+ throw new KeyManagementException(e);
} catch (KeyStoreException e) {
- return null;
+ throw new KeyManagementException(e);
} catch (UnrecoverableKeyException e) {
- return null;
+ throw new KeyManagementException(e);
}
}
- private static X509KeyManager findX509KeyManager(KeyManager[] kms) {
+ private static X509KeyManager findX509KeyManager(KeyManager[] kms) throws KeyManagementException {
for (KeyManager km : kms) {
if (km instanceof X509KeyManager) {
return (X509KeyManager)km;
}
}
- return null;
+ throw new KeyManagementException("Failed to find an X509KeyManager in " + Arrays.toString(kms));
}
/**
@@ -391,7 +386,7 @@
*
* TODO: Move this to a published API under dalvik.system.
*/
- public static X509TrustManager getDefaultTrustManager() {
+ public static X509TrustManager getDefaultTrustManager() throws KeyManagementException {
X509TrustManager result = defaultTrustManager;
if (result == null) {
// single-check idiom
@@ -399,7 +394,7 @@
}
return result;
}
- private static X509TrustManager createDefaultTrustManager() {
+ private static X509TrustManager createDefaultTrustManager() throws KeyManagementException {
try {
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
@@ -408,17 +403,17 @@
X509TrustManager trustManager = findX509TrustManager(tms);
return trustManager;
} catch (NoSuchAlgorithmException e) {
- return null;
+ throw new KeyManagementException(e);
} catch (KeyStoreException e) {
- return null;
+ throw new KeyManagementException(e);
}
}
- private static X509TrustManager findX509TrustManager(TrustManager[] tms) {
+ private static X509TrustManager findX509TrustManager(TrustManager[] tms) throws KeyManagementException {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
return (X509TrustManager)tm;
}
}
- return null;
+ throw new KeyManagementException("Failed to find an X509TrustManager in " + Arrays.toString(tms));
}
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLRecordProtocol.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLRecordProtocol.java
index abec7d1..e9f77f72 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLRecordProtocol.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLRecordProtocol.java
@@ -442,7 +442,7 @@
/**
* Sets up the SSL version used in this connection.
* This method is calling from the handshake protocol after
- * it becomes known witch protocol version will be used.
+ * it becomes known which protocol version will be used.
* @param ver: byte[]
* @return
*/
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
index b6a65b4..c5e1838 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerHandshakeImpl.java
@@ -205,8 +205,10 @@
Cipher c = null;
try {
c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
- c.init(Cipher.DECRYPT_MODE, privKey);
- preMasterSecret = c.doFinal(clientKeyExchange.exchange_keys);
+ c.init(Cipher.UNWRAP_MODE, privKey);
+ preMasterSecret = c.unwrap(clientKeyExchange.exchange_keys,
+ "preMasterSecret",
+ Cipher.SECRET_KEY).getEncoded();
// check preMasterSecret:
if (preMasterSecret.length != 48
|| preMasterSecret[0] != clientHello.client_version[0]
@@ -330,11 +332,17 @@
"HANDSHAKE FAILURE. Incorrect client hello message");
}
+ byte[] server_version = clientHello.client_version;
if (!ProtocolVersion.isSupported(clientHello.client_version)) {
- fatalAlert(AlertProtocol.PROTOCOL_VERSION,
- "PROTOCOL VERSION. Unsupported client version "
- + clientHello.client_version[0]
- + clientHello.client_version[1]);
+ if (clientHello.client_version[0] >= 3) {
+ // Protocol from the future, admit that the newest thing we know is TLSv1
+ server_version = ProtocolVersion.TLSv1.version;
+ } else {
+ fatalAlert(AlertProtocol.PROTOCOL_VERSION,
+ "PROTOCOL VERSION. Unsupported client version "
+ + clientHello.client_version[0]
+ + clientHello.client_version[1]);
+ }
}
isResuming = false;
@@ -404,13 +412,13 @@
}
}
- recordProtocol.setVersion(clientHello.client_version);
- session.protocol = ProtocolVersion.getByVersion(clientHello.client_version);
+ recordProtocol.setVersion(server_version);
+ session.protocol = ProtocolVersion.getByVersion(server_version);
session.clientRandom = clientHello.random;
// create server hello message
serverHello = new ServerHello(parameters.getSecureRandom(),
- clientHello.client_version,
+ server_version,
session.getId(), cipher_suite, (byte) 0); //CompressionMethod.null
session.serverRandom = serverHello.random;
send(serverHello);
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java
index cb21be4..f5716c1 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java
@@ -37,6 +37,12 @@
// TODO override trimToSize and removeEldestEntry to use
// SSL_CTX_sessions to remove from native cache
+
+ // Set a trivial session id context. OpenSSL uses this to make
+ // sure you don't reuse sessions externalized with i2d_SSL_SESSION
+ // between apps. However our sessions are either in memory or
+ // exported to a app's SSLServerSessionCache.
+ NativeCrypto.SSL_CTX_set_session_id_context(sslCtxNativePointer, new byte[] { ' ' });
}
public void setPersistentCache(SSLServerSessionCache persistentCache) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
index 653dca4..3f362c5 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
@@ -163,6 +163,14 @@
checkTrusted(chain, authType);
}
+ public void handleTrustStorageUpdate() {
+ if (acceptedIssuers == null) {
+ trustedCertificateIndex.reset();
+ } else {
+ trustedCertificateIndex.reset(trustAnchors(acceptedIssuers));
+ }
+ }
+
private void checkTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateIndex.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateIndex.java
index 9138b19..0b1f098 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateIndex.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateIndex.java
@@ -74,6 +74,19 @@
}
}
+ public void reset() {
+ synchronized (subjectToTrustAnchors) {
+ subjectToTrustAnchors.clear();
+ }
+ }
+
+ public void reset(Set<TrustAnchor> anchors) {
+ synchronized (subjectToTrustAnchors) {
+ reset();
+ index(anchors);
+ }
+ }
+
public TrustAnchor findByIssuerAndSignature(X509Certificate cert) {
X500Principal issuer = cert.getIssuerX500Principal();
synchronized (subjectToTrustAnchors) {
diff --git a/luni/src/main/native/AsynchronousSocketCloseMonitor.cpp b/luni/src/main/native/AsynchronousSocketCloseMonitor.cpp
index 0cfb8bb..7b0f602 100644
--- a/luni/src/main/native/AsynchronousSocketCloseMonitor.cpp
+++ b/luni/src/main/native/AsynchronousSocketCloseMonitor.cpp
@@ -53,7 +53,7 @@
sa.sa_flags = 0;
int rc = sigaction(BLOCKED_THREAD_SIGNAL, &sa, NULL);
if (rc == -1) {
- LOGE("setting blocked thread signal handler failed: %s", strerror(errno));
+ ALOGE("setting blocked thread signal handler failed: %s", strerror(errno));
}
}
diff --git a/luni/src/main/native/JniConstants.cpp b/luni/src/main/native/JniConstants.cpp
index c09f559..6815734 100644
--- a/luni/src/main/native/JniConstants.cpp
+++ b/luni/src/main/native/JniConstants.cpp
@@ -65,7 +65,7 @@
ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
if (result == NULL) {
- LOGE("failed to find class '%s'", name);
+ ALOGE("failed to find class '%s'", name);
abort();
}
return result;
diff --git a/luni/src/main/native/NetworkUtilities.cpp b/luni/src/main/native/NetworkUtilities.cpp
index 3b5b840..9f4d770 100644
--- a/luni/src/main/native/NetworkUtilities.cpp
+++ b/luni/src/main/native/NetworkUtilities.cpp
@@ -35,7 +35,7 @@
const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(ss);
if (ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
// Copy the IPv6 address into the temporary sockaddr_storage.
- memcpy(&tmp, ss, sizeof(tmp));
+ memcpy(&tmp, ss, sizeof(sockaddr_in6));
// Unmap it into an IPv4 address.
sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&tmp);
sin->sin_family = AF_INET;
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index a637a73..36abd7b 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -21,93 +21,56 @@
#include <stdlib.h>
-extern int register_java_io_Console(JNIEnv* env);
-extern int register_java_io_File(JNIEnv* env);
-extern int register_java_io_ObjectStreamClass(JNIEnv* env);
-extern int register_java_lang_Character(JNIEnv* env);
-extern int register_java_lang_Math(JNIEnv* env);
-extern int register_java_lang_ProcessManager(JNIEnv* env);
-extern int register_java_lang_RealToString(JNIEnv* env);
-extern int register_java_lang_StrictMath(JNIEnv* env);
-extern int register_java_lang_StringToReal(JNIEnv* env);
-extern int register_java_lang_System(JNIEnv* env);
-extern int register_java_math_NativeBN(JNIEnv* env);
-extern int register_java_nio_ByteOrder(JNIEnv* env);
-extern int register_java_nio_charset_Charsets(JNIEnv* env);
-extern int register_java_text_Bidi(JNIEnv* env);
-extern int register_java_util_regex_Matcher(JNIEnv* env);
-extern int register_java_util_regex_Pattern(JNIEnv* env);
-extern int register_java_util_zip_Adler32(JNIEnv* env);
-extern int register_java_util_zip_CRC32(JNIEnv* env);
-extern int register_java_util_zip_Deflater(JNIEnv* env);
-extern int register_java_util_zip_Inflater(JNIEnv* env);
-extern int register_libcore_icu_ICU(JNIEnv* env);
-extern int register_libcore_icu_NativeBreakIterator(JNIEnv* env);
-extern int register_libcore_icu_NativeCollation(JNIEnv* env);
-extern int register_libcore_icu_NativeConverter(JNIEnv* env);
-extern int register_libcore_icu_NativeDecimalFormat(JNIEnv* env);
-extern int register_libcore_icu_NativeIDN(JNIEnv* env);
-extern int register_libcore_icu_NativeNormalizer(JNIEnv* env);
-extern int register_libcore_icu_NativePluralRules(JNIEnv* env);
-extern int register_libcore_icu_TimeZones(JNIEnv* env);
-extern int register_libcore_io_AsynchronousCloseMonitor(JNIEnv* env);
-extern int register_libcore_io_Memory(JNIEnv* env);
-extern int register_libcore_io_OsConstants(JNIEnv* env);
-extern int register_libcore_io_Posix(JNIEnv* env);
-extern int register_libcore_net_RawSocket(JNIEnv* env);
-extern int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env);
-extern int register_org_apache_harmony_xml_ExpatParser(JNIEnv* env);
-extern int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env);
-
// DalvikVM calls this on startup, so we can statically register all our native methods.
-int registerCoreLibrariesJni(JNIEnv* env) {
+int JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("JavaVM::GetEnv() failed");
+ abort();
+ }
+
ScopedLocalFrame localFrame(env);
JniConstants::init(env);
- bool result =
- register_java_io_Console(env) != -1 &&
- register_java_io_File(env) != -1 &&
- register_java_io_ObjectStreamClass(env) != -1 &&
- register_java_lang_Character(env) != -1 &&
- register_java_lang_Math(env) != -1 &&
- register_java_lang_ProcessManager(env) != -1 &&
- register_java_lang_RealToString(env) != -1 &&
- register_java_lang_StrictMath(env) != -1 &&
- register_java_lang_StringToReal(env) != -1 &&
- register_java_lang_System(env) != -1 &&
- register_java_math_NativeBN(env) != -1 &&
- register_java_nio_ByteOrder(env) != -1 &&
- register_java_nio_charset_Charsets(env) != -1 &&
- register_java_text_Bidi(env) != -1 &&
- register_java_util_regex_Matcher(env) != -1 &&
- register_java_util_regex_Pattern(env) != -1 &&
- register_java_util_zip_Adler32(env) != -1 &&
- register_java_util_zip_CRC32(env) != -1 &&
- register_java_util_zip_Deflater(env) != -1 &&
- register_java_util_zip_Inflater(env) != -1 &&
- register_libcore_icu_ICU(env) != -1 &&
- register_libcore_icu_NativeBreakIterator(env) != -1 &&
- register_libcore_icu_NativeCollation(env) != -1 &&
- register_libcore_icu_NativeConverter(env) != -1 &&
- register_libcore_icu_NativeDecimalFormat(env) != -1 &&
- register_libcore_icu_NativeIDN(env) != -1 &&
- register_libcore_icu_NativeNormalizer(env) != -1 &&
- register_libcore_icu_NativePluralRules(env) != -1 &&
- register_libcore_icu_TimeZones(env) != -1 &&
- register_libcore_io_AsynchronousCloseMonitor(env) != -1 &&
- register_libcore_io_Memory(env) != -1 &&
- register_libcore_io_OsConstants(env) != -1 &&
- register_libcore_io_Posix(env) != -1 &&
- register_libcore_net_RawSocket(env) != -1 &&
- register_org_apache_harmony_dalvik_NativeTestTarget(env) != -1 &&
- register_org_apache_harmony_xml_ExpatParser(env) != -1 &&
- register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(env) != -1 &&
- true;
-
- if (!result) {
- LOGE("Failed to initialize the core libraries; aborting...");
- abort();
- }
- return 0;
+#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
+ REGISTER(register_java_io_Console);
+ REGISTER(register_java_io_File);
+ REGISTER(register_java_io_ObjectStreamClass);
+ REGISTER(register_java_lang_Character);
+ REGISTER(register_java_lang_Math);
+ REGISTER(register_java_lang_ProcessManager);
+ REGISTER(register_java_lang_RealToString);
+ REGISTER(register_java_lang_StrictMath);
+ REGISTER(register_java_lang_StringToReal);
+ REGISTER(register_java_lang_System);
+ REGISTER(register_java_math_NativeBN);
+ REGISTER(register_java_nio_ByteOrder);
+ REGISTER(register_java_nio_charset_Charsets);
+ REGISTER(register_java_text_Bidi);
+ REGISTER(register_java_util_regex_Matcher);
+ REGISTER(register_java_util_regex_Pattern);
+ REGISTER(register_java_util_zip_Adler32);
+ REGISTER(register_java_util_zip_CRC32);
+ REGISTER(register_java_util_zip_Deflater);
+ REGISTER(register_java_util_zip_Inflater);
+ REGISTER(register_libcore_icu_ICU);
+ REGISTER(register_libcore_icu_NativeBreakIterator);
+ REGISTER(register_libcore_icu_NativeCollation);
+ REGISTER(register_libcore_icu_NativeConverter);
+ REGISTER(register_libcore_icu_NativeDecimalFormat);
+ REGISTER(register_libcore_icu_NativeIDN);
+ REGISTER(register_libcore_icu_NativeNormalizer);
+ REGISTER(register_libcore_icu_NativePluralRules);
+ REGISTER(register_libcore_icu_TimeZones);
+ REGISTER(register_libcore_io_AsynchronousCloseMonitor);
+ REGISTER(register_libcore_io_Memory);
+ REGISTER(register_libcore_io_OsConstants);
+ REGISTER(register_libcore_io_Posix);
+ REGISTER(register_libcore_net_RawSocket);
+ REGISTER(register_org_apache_harmony_dalvik_NativeTestTarget);
+ REGISTER(register_org_apache_harmony_xml_ExpatParser);
+ REGISTER(register_org_apache_harmony_xnet_provider_jsse_NativeCrypto);
+#undef REGISTER
+ return JNI_VERSION_1_6;
}
diff --git a/luni/src/main/native/java_io_Console.cpp b/luni/src/main/native/java_io_Console.cpp
index 9150fb7..512bc72 100644
--- a/luni/src/main/native/java_io_Console.cpp
+++ b/luni/src/main/native/java_io_Console.cpp
@@ -46,6 +46,6 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Console, setEchoImpl, "(ZI)I"),
};
-int register_java_io_Console(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/io/Console", gMethods, NELEM(gMethods));
+void register_java_io_Console(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/io/Console", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_io_File.cpp b/luni/src/main/native/java_io_File.cpp
index db88a11..ba1f55a 100644
--- a/luni/src/main/native/java_io_File.cpp
+++ b/luni/src/main/native/java_io_File.cpp
@@ -104,6 +104,9 @@
// Returns the next filename, or NULL.
const char* next() {
+ if (mIsBad) {
+ return NULL;
+ }
dirent* result = NULL;
int rc = readdir_r(mDirStream, &mEntry, &result);
if (rc != 0) {
@@ -139,9 +142,6 @@
}
ScopedReaddir dir(path.c_str());
- if (dir.isBad()) {
- return false;
- }
const char* filename;
while ((filename = dir.next()) != NULL) {
if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0) {
@@ -149,7 +149,7 @@
entries.push_back(filename);
}
}
- return true;
+ return !dir.isBad();
}
static jobjectArray File_listImpl(JNIEnv* env, jclass, jstring javaPath) {
@@ -168,6 +168,6 @@
NATIVE_METHOD(File, realpath, "(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(File, setLastModifiedImpl, "(Ljava/lang/String;J)Z"),
};
-int register_java_io_File(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/io/File", gMethods, NELEM(gMethods));
+void register_java_io_File(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/io/File", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_io_ObjectStreamClass.cpp b/luni/src/main/native/java_io_ObjectStreamClass.cpp
index 721136e..f6bd560 100644
--- a/luni/src/main/native/java_io_ObjectStreamClass.cpp
+++ b/luni/src/main/native/java_io_ObjectStreamClass.cpp
@@ -63,6 +63,6 @@
NATIVE_METHOD(ObjectStreamClass, hasClinit, "(Ljava/lang/Class;)Z"),
NATIVE_METHOD(ObjectStreamClass, newInstance, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
};
-int register_java_io_ObjectStreamClass(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/io/ObjectStreamClass", gMethods, NELEM(gMethods));
+void register_java_io_ObjectStreamClass(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/io/ObjectStreamClass", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_Character.cpp b/luni/src/main/native/java_lang_Character.cpp
index 2ec029e..7dbef90 100644
--- a/luni/src/main/native/java_lang_Character.cpp
+++ b/luni/src/main/native/java_lang_Character.cpp
@@ -160,6 +160,6 @@
NATIVE_METHOD(Character, toTitleCaseImpl, "!(I)I"),
NATIVE_METHOD(Character, toUpperCaseImpl, "!(I)I"),
};
-int register_java_lang_Character(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/Character", gMethods, NELEM(gMethods));
+void register_java_lang_Character(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/Character", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_Math.cpp b/luni/src/main/native/java_lang_Math.cpp
index 4a41af2..273820e 100644
--- a/luni/src/main/native/java_lang_Math.cpp
+++ b/luni/src/main/native/java_lang_Math.cpp
@@ -131,6 +131,6 @@
NATIVE_METHOD(Math, tanh, "!(D)D"),
};
-int register_java_lang_Math(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/Math", gMethods, NELEM(gMethods));
+void register_java_lang_Math(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/Math", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_ProcessManager.cpp b/luni/src/main/native/java_lang_ProcessManager.cpp
index 5d59f27..6302d13 100644
--- a/luni/src/main/native/java_lang_ProcessManager.cpp
+++ b/luni/src/main/native/java_lang_ProcessManager.cpp
@@ -255,7 +255,7 @@
// Re-throw exception if present.
if (exception != NULL) {
if (env->Throw(exception) < 0) {
- LOGE("Error rethrowing exception!");
+ ALOGE("Error rethrowing exception!");
}
}
@@ -265,6 +265,6 @@
static JNINativeMethod methods[] = {
NATIVE_METHOD(ProcessManager, exec, "([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Z)I"),
};
-int register_java_lang_ProcessManager(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/ProcessManager", methods, NELEM(methods));
+void register_java_lang_ProcessManager(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/ProcessManager", methods, NELEM(methods));
}
diff --git a/luni/src/main/native/java_lang_RealToString.cpp b/luni/src/main/native/java_lang_RealToString.cpp
index 835151e..7036fe8 100644
--- a/luni/src/main/native/java_lang_RealToString.cpp
+++ b/luni/src/main/native/java_lang_RealToString.cpp
@@ -237,6 +237,6 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(RealToString, bigIntDigitGenerator, "(JIZI)V"),
};
-int register_java_lang_RealToString(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/RealToString", gMethods, NELEM(gMethods));
+void register_java_lang_RealToString(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/RealToString", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_StrictMath.cpp b/luni/src/main/native/java_lang_StrictMath.cpp
index 6df3f01..959ddc6 100644
--- a/luni/src/main/native/java_lang_StrictMath.cpp
+++ b/luni/src/main/native/java_lang_StrictMath.cpp
@@ -145,6 +145,6 @@
NATIVE_METHOD(StrictMath, tanh, "!(D)D"),
};
-int register_java_lang_StrictMath(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/StrictMath", gMethods, NELEM(gMethods));
+void register_java_lang_StrictMath(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/StrictMath", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_StringToReal.cpp b/luni/src/main/native/java_lang_StringToReal.cpp
index 5dc096e..d401e65 100644
--- a/luni/src/main/native/java_lang_StringToReal.cpp
+++ b/luni/src/main/native/java_lang_StringToReal.cpp
@@ -1008,6 +1008,6 @@
NATIVE_METHOD(StringToReal, parseFltImpl, "(Ljava/lang/String;I)F"),
NATIVE_METHOD(StringToReal, parseDblImpl, "(Ljava/lang/String;I)D"),
};
-int register_java_lang_StringToReal(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/StringToReal", gMethods, NELEM(gMethods));
+void register_java_lang_StringToReal(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/StringToReal", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_lang_System.cpp b/luni/src/main/native/java_lang_System.cpp
index 9ebfc32..8cfd070 100644
--- a/luni/src/main/native/java_lang_System.cpp
+++ b/luni/src/main/native/java_lang_System.cpp
@@ -36,7 +36,7 @@
ScopedUtfChars message(env, javaMessage);
if (message.c_str() == NULL) {
// Since this function is used for last-gasp debugging output, be noisy on failure.
- LOGE("message.c_str() == NULL");
+ ALOGE("message.c_str() == NULL");
return;
}
int priority;
@@ -88,6 +88,6 @@
NATIVE_METHOD(System, setFieldImpl, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"),
NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
};
-int register_java_lang_System(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
+void register_java_lang_System(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_math_NativeBN.cpp b/luni/src/main/native/java_math_NativeBN.cpp
index 6359e3e..5e111d7 100644
--- a/luni/src/main/native/java_math_NativeBN.cpp
+++ b/luni/src/main/native/java_math_NativeBN.cpp
@@ -405,7 +405,7 @@
}
static jboolean NativeBN_modifyBit(JNIEnv* env, jclass, BIGNUM* a, int n, int op) {
-// LOGD("NativeBN_BN_modifyBit");
+// ALOGD("NativeBN_BN_modifyBit");
if (!oneValidHandle(env, a)) return JNI_FALSE;
switch (op) {
case 1: return BN_set_bit(a, n);
@@ -553,6 +553,6 @@
NATIVE_METHOD(NativeBN, sign, "(I)I"),
NATIVE_METHOD(NativeBN, twosComp2bn, "([BII)Z"),
};
-int register_java_math_NativeBN(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
+void register_java_math_NativeBN(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_nio_ByteOrder.cpp b/luni/src/main/native/java_nio_ByteOrder.cpp
index b1695a9..3269bc2 100644
--- a/luni/src/main/native/java_nio_ByteOrder.cpp
+++ b/luni/src/main/native/java_nio_ByteOrder.cpp
@@ -27,6 +27,6 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(ByteOrder, isLittleEndian, "!()Z"),
};
-int register_java_nio_ByteOrder(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/nio/ByteOrder", gMethods, NELEM(gMethods));
+void register_java_nio_ByteOrder(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/nio/ByteOrder", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_nio_charset_Charsets.cpp b/luni/src/main/native/java_nio_charset_Charsets.cpp
index 22422fe..a49ba22 100644
--- a/luni/src/main/native/java_nio_charset_Charsets.cpp
+++ b/luni/src/main/native/java_nio_charset_Charsets.cpp
@@ -245,6 +245,6 @@
NATIVE_METHOD(Charsets, toIsoLatin1Bytes, "([CII)[B"),
NATIVE_METHOD(Charsets, toUtf8Bytes, "([CII)[B"),
};
-int register_java_nio_charset_Charsets(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/nio/charset/Charsets", gMethods, NELEM(gMethods));
+void register_java_nio_charset_Charsets(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/nio/charset/Charsets", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_text_Bidi.cpp b/luni/src/main/native/java_text_Bidi.cpp
index 27d3ddb..93c02bb 100644
--- a/luni/src/main/native/java_text_Bidi.cpp
+++ b/luni/src/main/native/java_text_Bidi.cpp
@@ -187,6 +187,6 @@
NATIVE_METHOD(Bidi, ubidi_setLine, "(JII)J"),
NATIVE_METHOD(Bidi, ubidi_setPara, "(J[CII[B)V"),
};
-int register_java_text_Bidi(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/text/Bidi", gMethods, NELEM(gMethods));
+void register_java_text_Bidi(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/text/Bidi", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 024a6f0..0f91bd5 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -211,6 +211,6 @@
NATIVE_METHOD(Matcher, useAnchoringBoundsImpl, "(IZ)V"),
NATIVE_METHOD(Matcher, useTransparentBoundsImpl, "(IZ)V"),
};
-int register_java_util_regex_Matcher(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/regex/Matcher", gMethods, NELEM(gMethods));
+void register_java_util_regex_Matcher(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/regex/Matcher", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index 1e0e1e3..cad154f 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -95,6 +95,6 @@
NATIVE_METHOD(Pattern, closeImpl, "(I)V"),
NATIVE_METHOD(Pattern, compileImpl, "(Ljava/lang/String;I)I"),
};
-int register_java_util_regex_Pattern(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/regex/Pattern", gMethods, NELEM(gMethods));
+void register_java_util_regex_Pattern(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/regex/Pattern", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_zip_Adler32.cpp b/luni/src/main/native/java_util_zip_Adler32.cpp
index d0c96ea..9358f26 100644
--- a/luni/src/main/native/java_util_zip_Adler32.cpp
+++ b/luni/src/main/native/java_util_zip_Adler32.cpp
@@ -40,6 +40,6 @@
NATIVE_METHOD(Adler32, updateImpl, "([BIIJ)J"),
NATIVE_METHOD(Adler32, updateByteImpl, "(IJ)J"),
};
-int register_java_util_zip_Adler32(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/zip/Adler32", gMethods, NELEM(gMethods));
+void register_java_util_zip_Adler32(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/Adler32", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_zip_CRC32.cpp b/luni/src/main/native/java_util_zip_CRC32.cpp
index ecfde7f..502a4ecf 100644
--- a/luni/src/main/native/java_util_zip_CRC32.cpp
+++ b/luni/src/main/native/java_util_zip_CRC32.cpp
@@ -40,6 +40,6 @@
NATIVE_METHOD(CRC32, updateImpl, "([BIIJ)J"),
NATIVE_METHOD(CRC32, updateByteImpl, "(BJ)J"),
};
-int register_java_util_zip_CRC32(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/zip/CRC32", gMethods, NELEM(gMethods));
+void register_java_util_zip_CRC32(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/CRC32", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_zip_Deflater.cpp b/luni/src/main/native/java_util_zip_Deflater.cpp
index 82d081b..e129134 100644
--- a/luni/src/main/native/java_util_zip_Deflater.cpp
+++ b/luni/src/main/native/java_util_zip_Deflater.cpp
@@ -146,6 +146,6 @@
NATIVE_METHOD(Deflater, setInputImpl, "([BIIJ)V"),
NATIVE_METHOD(Deflater, setLevelsImpl, "(IIJ)V"),
};
-int register_java_util_zip_Deflater(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
+void register_java_util_zip_Deflater(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/java_util_zip_Inflater.cpp b/luni/src/main/native/java_util_zip_Inflater.cpp
index 192d1b5..890c6dc 100644
--- a/luni/src/main/native/java_util_zip_Inflater.cpp
+++ b/luni/src/main/native/java_util_zip_Inflater.cpp
@@ -168,6 +168,6 @@
NATIVE_METHOD(Inflater, setFileInputImpl, "(Ljava/io/FileDescriptor;JIJ)I"),
NATIVE_METHOD(Inflater, setInputImpl, "([BIIJ)V"),
};
-int register_java_util_zip_Inflater(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "java/util/zip/Inflater", gMethods, NELEM(gMethods));
+void register_java_util_zip_Inflater(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/zip/Inflater", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 9f96f42..5a07694 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -135,7 +135,7 @@
ScopedResourceBundle currencyElem(ures_getByIndex(currency.get(), 0, NULL, &status));
if (U_FAILURE(status)) {
- return env->NewStringUTF("None");
+ return env->NewStringUTF("XXX");
}
// Check if there's a 'to' date. If there is, the currency isn't used anymore.
@@ -149,12 +149,12 @@
ScopedResourceBundle currencyId(ures_getByKey(currencyElem.get(), "id", NULL, &status));
if (U_FAILURE(status)) {
// No id defined for this country
- return env->NewStringUTF("None");
+ return env->NewStringUTF("XXX");
}
int32_t charCount;
const jchar* chars = ures_getString(currencyId.get(), &charCount, &status);
- return (charCount == 0) ? env->NewStringUTF("None") : env->NewString(chars, charCount);
+ return (charCount == 0) ? env->NewStringUTF("XXX") : env->NewString(chars, charCount);
}
static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaCurrencyCode) {
@@ -269,97 +269,6 @@
return toStringArray(env, unum_countAvailable, unum_getAvailable);
}
-static bool getDayIntVector(JNIEnv*, UResourceBundle* gregorian, int* values) {
- // get the First day of week and the minimal days in first week numbers
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle gregorianElems(ures_getByKey(gregorian, "DateTimeElements", NULL, &status));
- if (U_FAILURE(status)) {
- return false;
- }
-
- int intVectSize;
- const int* result = ures_getIntVector(gregorianElems.get(), &intVectSize, &status);
- if (U_FAILURE(status) || intVectSize != 2) {
- return false;
- }
-
- values[0] = result[0];
- values[1] = result[1];
- return true;
-}
-
-// This allows you to leave extra space at the beginning or end of the array to support the
-// month names and day names arrays.
-static jobjectArray toStringArray(JNIEnv* env, UResourceBundle* rb, size_t size, int capacity, size_t offset) {
- if (capacity == -1) {
- capacity = size;
- }
- jobjectArray result = env->NewObjectArray(capacity, JniConstants::stringClass, NULL);
- if (result == NULL) {
- return NULL;
- }
- UErrorCode status = U_ZERO_ERROR;
- for (size_t i = 0; i < size; ++i) {
- int charCount;
- const jchar* chars = ures_getStringByIndex(rb, i, &charCount, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- ScopedLocalRef<jstring> s(env, env->NewString(chars, charCount));
- if (env->ExceptionCheck()) {
- return NULL;
- }
- env->SetObjectArrayElement(result, offset + i, s.get());
- if (env->ExceptionCheck()) {
- return NULL;
- }
- }
- return result;
-}
-
-static jobjectArray getAmPmMarkers(JNIEnv* env, UResourceBundle* gregorian) {
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle amPmMarkers(ures_getByKey(gregorian, "AmPmMarkers", NULL, &status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- return toStringArray(env, amPmMarkers.get(), ures_getSize(amPmMarkers.get()), -1, 0);
-}
-
-static jobjectArray getEras(JNIEnv* env, UResourceBundle* gregorian) {
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle eras(ures_getByKey(gregorian, "eras", NULL, &status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- ScopedResourceBundle abbreviatedEras(ures_getByKey(eras.get(), "abbreviated", NULL, &status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- return toStringArray(env, abbreviatedEras.get(), ures_getSize(abbreviatedEras.get()), -1, 0);
-}
-
-enum NameType { REGULAR, STAND_ALONE };
-enum NameWidth { LONG, SHORT };
-static jobjectArray getNames(JNIEnv* env, UResourceBundle* namesBundle, bool months, NameType type, NameWidth width) {
- const char* typeKey = (type == REGULAR) ? "format" : "stand-alone";
- const char* widthKey = (width == LONG) ? "wide" : "abbreviated";
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle formatBundle(ures_getByKey(namesBundle, typeKey, NULL, &status));
- ScopedResourceBundle valuesBundle(ures_getByKey(formatBundle.get(), widthKey, NULL, &status));
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- // The months array has a trailing empty string. The days array has a leading empty string.
- int count = ures_getSize(valuesBundle.get());
- int offset = months ? 0 : 1;
- jobjectArray result = toStringArray(env, valuesBundle.get(), count, count + 1, offset);
- ScopedLocalRef<jstring> emptyString(env, env->NewStringUTF(""));
- env->SetObjectArrayElement(result, months ? count : 0, emptyString.get());
- return result;
-}
-
static void setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "Ljava/lang/Integer;");
@@ -377,6 +286,21 @@
env->SetObjectField(obj, fid, value);
}
+static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString* valueArray, int32_t size) {
+ ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(size, JniConstants::stringClass, NULL));
+ for (int32_t i = 0; i < size ; i++) {
+ ScopedLocalRef<jstring> s(env, env->NewString(valueArray[i].getBuffer(),valueArray[i].length()));
+ if (env->ExceptionCheck()) {
+ return;
+ }
+ env->SetObjectArrayElement(result.get(), i, s.get());
+ if (env->ExceptionCheck()) {
+ return;
+ }
+ }
+ setStringArrayField(env, obj, fieldName, result.get());
+}
+
static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
UErrorCode status = U_ZERO_ERROR;
int charCount;
@@ -384,168 +308,57 @@
if (U_SUCCESS(status)) {
setStringField(env, obj, fieldName, env->NewString(chars, charCount));
} else {
- LOGE("Error setting String field %s from ICU resource: %s", fieldName, u_errorName(status));
+ ALOGE("Error setting String field %s from ICU resource: %s", fieldName, u_errorName(status));
}
}
-static bool setStringField(JNIEnv* env, jobject obj, const char* key, const char* fieldName, UResourceBundle* bundle) {
- if (bundle == NULL) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- int charCount;
- const UChar* chars = ures_getStringByKey(bundle, key, &charCount, &status);
- if (U_SUCCESS(status)) {
- setStringField(env, obj, fieldName, env->NewString(chars, charCount));
- return true;
- } else {
- // Missing item in current resource bundle but not an error.
- return false;
- }
-}
-
-static void setStringField(JNIEnv* env, jobject obj, const char* key, const char* fieldName,
- UResourceBundle* bundle, UResourceBundle* fallbackBundle) {
- if (!setStringField(env, obj, key, fieldName, bundle) && fallbackBundle != NULL) {
- setStringField(env, obj, key, fieldName, fallbackBundle);
- }
-}
-
-static bool setCharField(JNIEnv* env, jobject obj, const char* key, const char* fieldName,
- UResourceBundle* bundle) {
- if (bundle == NULL) {
- return false;
- }
- UErrorCode status = U_ZERO_ERROR;
- int charCount;
- const UChar* chars = ures_getStringByKey(bundle, key, &charCount, &status);
- if (U_SUCCESS(status)) {
- jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "C");
- env->SetCharField(obj, fid, chars[0]);
- return true;
- } else {
- // Missing item in current resource bundle but not an error.
- return false;
- }
-}
-
-static void setCharField(JNIEnv* env, jobject obj, const char* key, const char* fieldName,
- UResourceBundle* bundle, UResourceBundle* fallbackBundle) {
- if (!setCharField(env, obj, key, fieldName, bundle) && fallbackBundle != NULL) {
- setCharField(env, obj, key, fieldName, fallbackBundle);
- }
-}
-
-static void setNumberSymbols(JNIEnv* env, jobject obj, UResourceBundle* numberSymbols, UResourceBundle* fallbackNumberSymbols) {
- setCharField(env, obj, "decimal", "decimalSeparator", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "group", "groupingSeparator", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "list", "patternSeparator", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "percentSign", "percent", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "perMille", "perMill", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "decimal", "monetarySeparator", numberSymbols, fallbackNumberSymbols);
- setCharField(env, obj, "minusSign", "minusSign", numberSymbols, fallbackNumberSymbols);
- setStringField(env, obj, "exponential", "exponentSeparator", numberSymbols, fallbackNumberSymbols);
- setStringField(env, obj, "infinity", "infinity", numberSymbols, fallbackNumberSymbols);
- setStringField(env, obj, "nan", "NaN", numberSymbols, fallbackNumberSymbols);
-}
-
-static void setZeroDigitToDefault(JNIEnv* env, jobject obj) {
- static jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, "zeroDigit", "C");
- env->SetCharField(obj, fid, '0');
-}
-
-static void setZeroDigit(JNIEnv* env, jobject obj, bool isLatn, char* buffer) {
- if (isLatn || buffer == NULL || buffer[0] == '\0') {
- return setZeroDigitToDefault(env, obj);
- }
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle numSystemRoot(ures_openDirect(NULL, "numberingSystems", &status));
- if (U_FAILURE(status)) {
- return setZeroDigitToDefault(env, obj);
- }
- ScopedResourceBundle numSystem(ures_getByKey(numSystemRoot.get(), "numberingSystems", NULL, &status));
- if (U_FAILURE(status)) {
- return setZeroDigitToDefault(env, obj);
- }
- ScopedResourceBundle nonLatnSystem(ures_getByKey(numSystem.get(), buffer, NULL, &status));
- if (U_FAILURE(status)) {
- return setZeroDigitToDefault(env, obj);
- }
- int32_t charCount = 0;
- const UChar* chars = ures_getStringByKey(nonLatnSystem.get(), "desc", &charCount, &status);
- if (charCount == 0) {
- setZeroDigitToDefault(env, obj);
- } else {
- static jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, "zeroDigit", "C");
- env->SetCharField(obj, fid, chars[0]);
- }
-}
-
-static void setNumberElements(JNIEnv* env, jobject obj, UResourceBundle* numberElements) {
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle latnNumberRB(ures_getByKey(numberElements, "latn", NULL, &status));
- if (U_FAILURE(status)) {
- LOGW("Error getting ICU latn number elements system value: %s", u_errorName(status));
+static void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString& value) {
+ if (value.length() == 0) {
return;
}
- ScopedResourceBundle patternsRB(ures_getByKey(latnNumberRB.get(), "patterns", NULL, &status));
- if (U_FAILURE(status)) {
- LOGW("Error getting ICU latn number patterns value: %s", u_errorName(status));
- return;
- }
- // Get the patterns from the 'latn' numberElements
- // This is a temporary workaround for ICU ticket#8611.
- UResourceBundle* bundle = patternsRB.get();
- setStringField(env, obj, "currencyFormat", "currencyPattern", bundle);
- setStringField(env, obj, "decimalFormat", "numberPattern", bundle);
- setStringField(env, obj, "percentFormat", "percentPattern", bundle);
+ jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "C");
+ env->SetCharField(obj, fid, value.charAt(0));
+}
- status = U_ZERO_ERROR;
- bool isLatn = false;
- char buffer[256];
- buffer[0] = '\0';
- ScopedResourceBundle defaultNumberElem(ures_getByKey(numberElements, "default", NULL, &status));
- if (U_SUCCESS(status)) {
- int32_t charCount = 256;
- ures_getUTF8String(defaultNumberElem.get(), buffer, &charCount, true, &status);
- buffer[charCount] = '\0';
- if (U_FAILURE(status)) {
- LOGW("Error getting ICU default number element system value: %s", u_errorName(status));
- // Use latn number symbols instead.
- isLatn = true;
- } else {
- isLatn = (strcmp(buffer, "latn") == 0);
- }
- } else {
- // Not default data, fallback to latn number elements.
- isLatn = true;
- }
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const UnicodeString& value) {
+ const UChar* chars = value.getBuffer();
+ setStringField(env, obj, fieldName, env->NewString(chars, value.length()));
+}
- status = U_ZERO_ERROR;
- setZeroDigit(env, obj, isLatn, buffer);
- if (isLatn) {
- ScopedResourceBundle symbolsRB(ures_getByKey(latnNumberRB.get(), "symbols", NULL, &status));
- if (U_SUCCESS(status)) {
- setNumberSymbols(env, obj, symbolsRB.get(), NULL);
- } else {
- LOGW("Missing ICU latn symbols system value: %s", u_errorName(status));
- }
- } else {
- // Get every symbol item from default numbering system first. If it does not
- // exist, get the symbol from latn numbering system.
- ScopedResourceBundle defaultNumberRB(ures_getByKey(numberElements, (const char*)buffer, NULL, &status));
- ScopedResourceBundle defaultSymbolsRB(ures_getByKey(defaultNumberRB.get(), "symbols", NULL, &status));
- if (U_FAILURE(status)) {
- LOGW("Missing ICU %s symbols system value: %s", buffer, u_errorName(status));
- isLatn = true; // Fallback to latn symbols.
- status = U_ZERO_ERROR;
- }
- ScopedResourceBundle latnSymbolsRB(ures_getByKey(latnNumberRB.get(), "symbols", NULL, &status));
- if (isLatn && U_FAILURE(status)) {
- return;
- }
- setNumberSymbols(env, obj, defaultSymbolsRB.get(), latnSymbolsRB.get());
- }
+static void setNumberPatterns(JNIEnv* env, jobject obj, jstring locale) {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale localeObj = getLocale(env, locale);
+
+ UnicodeString pattern;
+ UniquePtr<DecimalFormat> fmt(static_cast<DecimalFormat*>(NumberFormat::createInstance(localeObj, UNUM_CURRENCY, status)));
+ pattern = fmt->toPattern(pattern.remove());
+ setStringField(env, obj, "currencyPattern", pattern);
+
+ fmt.reset(static_cast<DecimalFormat*>(NumberFormat::createInstance(localeObj, UNUM_DECIMAL, status)));
+ pattern = fmt->toPattern(pattern.remove());
+ setStringField(env, obj, "numberPattern", pattern);
+
+ fmt.reset(static_cast<DecimalFormat*>(NumberFormat::createInstance(localeObj, UNUM_PERCENT, status)));
+ pattern = fmt->toPattern(pattern.remove());
+ setStringField(env, obj, "percentPattern", pattern);
+}
+
+static void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, jstring locale) {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale localeObj = getLocale(env, locale);
+ DecimalFormatSymbols dfs(localeObj, status);
+
+ setCharField(env, obj, "decimalSeparator", dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ setCharField(env, obj, "groupingSeparator", dfs.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
+ setCharField(env, obj, "patternSeparator", dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
+ setCharField(env, obj, "percent", dfs.getSymbol(DecimalFormatSymbols::kPercentSymbol));
+ setCharField(env, obj, "perMill", dfs.getSymbol(DecimalFormatSymbols::kPerMillSymbol));
+ setCharField(env, obj, "monetarySeparator", dfs.getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol));
+ setCharField(env, obj, "minusSign", dfs.getSymbol(DecimalFormatSymbols:: kMinusSignSymbol));
+ setStringField(env, obj, "exponentSeparator", dfs.getSymbol(DecimalFormatSymbols::kExponentialSymbol));
+ setStringField(env, obj, "infinity", dfs.getSymbol(DecimalFormatSymbols::kInfinitySymbol));
+ setStringField(env, obj, "NaN", dfs.getSymbol(DecimalFormatSymbols::kNaNSymbol));
+ setCharField(env, obj, "zeroDigit", dfs.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
}
static jboolean ICU_initLocaleDataImpl(JNIEnv* env, jclass, jstring locale, jobject localeData) {
@@ -554,96 +367,110 @@
return JNI_FALSE;
}
- UErrorCode status = U_ZERO_ERROR;
- ScopedResourceBundle root(ures_open(NULL, localeName.c_str(), &status));
+ // Get DateTimePatterns
+ UErrorCode status;
+ char currentLocale[ULOC_FULLNAME_CAPACITY];
+ int32_t localeNameLen = 0;
+ if (localeName.size() >= ULOC_FULLNAME_CAPACITY) {
+ return JNI_FALSE; // Exceed ICU defined limit of the whole locale ID.
+ }
+ strcpy(currentLocale, localeName.c_str());
+ do {
+ status = U_ZERO_ERROR;
+ ScopedResourceBundle root(ures_open(NULL, currentLocale, &status));
+ if (U_FAILURE(status)) {
+ if (localeNameLen == 0) {
+ break; // No parent locale, report this error outside the loop.
+ } else {
+ status = U_ZERO_ERROR;
+ continue; // get parent locale.
+ }
+ }
+ ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue; // get parent locale.
+ }
+
+ ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue; // get parent locale.
+ }
+ ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
+ if (U_SUCCESS(status)) {
+ setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
+ setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
+ setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
+ setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
+ setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
+ setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
+ setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
+ setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
+ break;
+ } else {
+ status = U_ZERO_ERROR; // get parent locale.
+ }
+ } while((localeNameLen = uloc_getParent(currentLocale, currentLocale, sizeof(currentLocale), &status)) >= 0);
if (U_FAILURE(status)) {
- LOGE("Error getting ICU resource bundle: %s", u_errorName(status));
+ ALOGE("Error getting ICU resource bundle: %s", u_errorName(status));
return JNI_FALSE;
}
- ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+ status = U_ZERO_ERROR;
+ Locale localeObj = getLocale(env, locale);
+
+ UniquePtr<Calendar> cal(Calendar::createInstance(localeObj, status));
if (U_FAILURE(status)) {
- LOGE("Error getting ICU calendar resource bundle: %s", u_errorName(status));
return JNI_FALSE;
}
+ setIntegerField(env, localeData, "firstDayOfWeek", cal->getFirstDayOfWeek());
+ setIntegerField(env, localeData, "minimalDaysInFirstWeek", cal->getMinimalDaysInFirstWeek());
- ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+ // Get DateFormatSymbols
+ status = U_ZERO_ERROR;
+ DateFormatSymbols dateFormatSym(localeObj, status);
if (U_FAILURE(status)) {
- LOGE("Error getting ICU gregorian resource bundle: %s", u_errorName(status));
return JNI_FALSE;
}
+ int32_t count = 0;
+ // Get AM/PM marker
+ const UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
+ setStringArrayField(env, localeData, "amPm", amPmStrs, count);
+ const UnicodeString* erasStrs = dateFormatSym.getEras(count);
+ setStringArrayField(env, localeData, "eras", erasStrs, count);
- int firstDayVals[] = { 0, 0 };
- if (getDayIntVector(env, gregorian.get(), firstDayVals)) {
- setIntegerField(env, localeData, "firstDayOfWeek", firstDayVals[0]);
- setIntegerField(env, localeData, "minimalDaysInFirstWeek", firstDayVals[1]);
- }
+ const UnicodeString* longMonthNames =
+ dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ setStringArrayField(env, localeData, "longMonthNames", longMonthNames, count);
+ const UnicodeString* shortMonthNames =
+ dateFormatSym.getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
+ const UnicodeString* longWeekdayNames =
+ dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
+ const UnicodeString* shortWeekdayNames =
+ dateFormatSym.getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
- jobjectArray amPmMarkers = getAmPmMarkers(env, gregorian.get());
- setStringArrayField(env, localeData, "amPm", amPmMarkers);
- env->DeleteLocalRef(amPmMarkers);
+ const UnicodeString* longStandAloneMonthNames =
+ dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames, count);
+ const UnicodeString* shortStandAloneMonthNames =
+ dateFormatSym.getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
+ const UnicodeString* longStandAloneWeekdayNames =
+ dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
+ const UnicodeString* shortStandAloneWeekdayNames =
+ dateFormatSym.getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
- jobjectArray eras = getEras(env, gregorian.get());
- setStringArrayField(env, localeData, "eras", eras);
- env->DeleteLocalRef(eras);
-
- ScopedResourceBundle dayNames(ures_getByKey(gregorian.get(), "dayNames", NULL, &status));
- ScopedResourceBundle monthNames(ures_getByKey(gregorian.get(), "monthNames", NULL, &status));
-
- // Get the regular month and weekday names.
- jobjectArray longMonthNames = getNames(env, monthNames.get(), true, REGULAR, LONG);
- jobjectArray shortMonthNames = getNames(env, monthNames.get(), true, REGULAR, SHORT);
- jobjectArray longWeekdayNames = getNames(env, dayNames.get(), false, REGULAR, LONG);
- jobjectArray shortWeekdayNames = getNames(env, dayNames.get(), false, REGULAR, SHORT);
- setStringArrayField(env, localeData, "longMonthNames", longMonthNames);
- setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames);
- setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames);
- setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames);
-
- // Get the stand-alone month and weekday names. If they're not available (as they aren't for
- // English), we reuse the regular names. If we returned null to Java, the usual fallback
- // mechanisms would come into play and we'd end up with the bogus stand-alone names from the
- // root locale ("1" for January, and so on).
- jobjectArray longStandAloneMonthNames = getNames(env, monthNames.get(), true, STAND_ALONE, LONG);
- if (longStandAloneMonthNames == NULL) {
- longStandAloneMonthNames = longMonthNames;
- }
- jobjectArray shortStandAloneMonthNames = getNames(env, monthNames.get(), true, STAND_ALONE, SHORT);
- if (shortStandAloneMonthNames == NULL) {
- shortStandAloneMonthNames = shortMonthNames;
- }
- jobjectArray longStandAloneWeekdayNames = getNames(env, dayNames.get(), false, STAND_ALONE, LONG);
- if (longStandAloneWeekdayNames == NULL) {
- longStandAloneWeekdayNames = longWeekdayNames;
- }
- jobjectArray shortStandAloneWeekdayNames = getNames(env, dayNames.get(), false, STAND_ALONE, SHORT);
- if (shortStandAloneWeekdayNames == NULL) {
- shortStandAloneWeekdayNames = shortWeekdayNames;
- }
- setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames);
- setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames);
- setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames);
- setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames);
-
- ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
- if (U_SUCCESS(status)) {
- setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
- setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
- setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
- setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
- setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
- setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
- setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
- setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
- }
status = U_ZERO_ERROR;
// For numberPatterns and symbols.
- ScopedResourceBundle numberElements(ures_getByKey(root.get(), "NumberElements", NULL, &status));
- if (U_SUCCESS(status)) {
- setNumberElements(env, localeData, numberElements.get());
- }
- status = U_ZERO_ERROR;
+ setNumberPatterns(env, localeData, locale);
+ setDecimalFormatSymbolsData(env, localeData, locale);
jstring countryCode = env->NewStringUTF(Locale::createFromName(localeName.c_str()).getCountry());
jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
@@ -750,7 +577,7 @@
NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
};
-int register_libcore_icu_ICU(JNIEnv* env) {
+void register_libcore_icu_ICU(JNIEnv* env) {
std::string path;
path = u_getDataDirectory();
path += "/";
@@ -758,12 +585,12 @@
path += ".dat";
#define FAIL_WITH_STRERROR(s) \
- LOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
- return -1;
+ ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
+ abort();
#define MAYBE_FAIL_WITH_ICU_ERROR(s) \
if (status != U_ZERO_ERROR) {\
- LOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
- return -1; \
+ ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
+ abort(); \
}
// Open the file and get its length.
@@ -800,5 +627,5 @@
// and bail.
u_init(&status);
MAYBE_FAIL_WITH_ICU_ERROR("u_init");
- return jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
index f74822d..d93c229 100644
--- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
+++ b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
@@ -220,6 +220,6 @@
NATIVE_METHOD(NativeBreakIterator, previousImpl, "(I)I"),
NATIVE_METHOD(NativeBreakIterator, setTextImpl, "(ILjava/lang/String;)V"),
};
-int register_libcore_icu_NativeBreakIterator(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeBreakIterator", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeBreakIterator(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeBreakIterator", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp
index 26e276e..3ed49e9 100644
--- a/luni/src/main/native/libcore_icu_NativeCollation.cpp
+++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp
@@ -194,6 +194,6 @@
NATIVE_METHOD(NativeCollation, setOffset, "(II)V"),
NATIVE_METHOD(NativeCollation, setText, "(ILjava/lang/String;)V"),
};
-int register_libcore_icu_NativeCollation(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeCollation", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeCollation(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeCollation", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index 6a7fbc5..5b3761e 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -608,6 +608,6 @@
NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)I"),
NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)I"),
};
-int register_libcore_icu_NativeConverter(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeConverter(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
index b68c822..1fe4055 100644
--- a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp
@@ -366,6 +366,6 @@
NATIVE_METHOD(NativeDecimalFormat, setTextAttribute, "(IILjava/lang/String;)V"),
NATIVE_METHOD(NativeDecimalFormat, toPatternImpl, "(IZ)Ljava/lang/String;"),
};
-int register_libcore_icu_NativeDecimalFormat(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeDecimalFormat", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeDecimalFormat(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeDecimalFormat", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeIDN.cpp b/luni/src/main/native/libcore_icu_NativeIDN.cpp
index 3d0cba3..16a6e1c 100644
--- a/luni/src/main/native/libcore_icu_NativeIDN.cpp
+++ b/luni/src/main/native/libcore_icu_NativeIDN.cpp
@@ -62,6 +62,6 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(NativeIDN, convertImpl, "(Ljava/lang/String;IZ)Ljava/lang/String;"),
};
-int register_libcore_icu_NativeIDN(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeIDN", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeIDN(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeIDN", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
index 57f31f4..58f460c 100644
--- a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
+++ b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp
@@ -45,6 +45,6 @@
NATIVE_METHOD(NativeNormalizer, normalizeImpl, "(Ljava/lang/String;I)Ljava/lang/String;"),
NATIVE_METHOD(NativeNormalizer, isNormalizedImpl, "(Ljava/lang/String;I)Z"),
};
-int register_libcore_icu_NativeNormalizer(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativeNormalizer", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativeNormalizer(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativeNormalizer", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativePluralRules.cpp b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
index 3a443d7..a7164d0 100644
--- a/luni/src/main/native/libcore_icu_NativePluralRules.cpp
+++ b/luni/src/main/native/libcore_icu_NativePluralRules.cpp
@@ -60,6 +60,6 @@
NATIVE_METHOD(NativePluralRules, forLocaleImpl, "(Ljava/lang/String;)I"),
NATIVE_METHOD(NativePluralRules, quantityForIntImpl, "(II)I"),
};
-int register_libcore_icu_NativePluralRules(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/NativePluralRules", gMethods, NELEM(gMethods));
+void register_libcore_icu_NativePluralRules(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/NativePluralRules", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_TimeZones.cpp b/luni/src/main/native/libcore_icu_TimeZones.cpp
index 9da108d..b543238 100644
--- a/luni/src/main/native/libcore_icu_TimeZones.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZones.cpp
@@ -226,6 +226,6 @@
NATIVE_METHOD(TimeZones, forCountryCode, "(Ljava/lang/String;)[Ljava/lang/String;"),
NATIVE_METHOD(TimeZones, getZoneStringsImpl, "(Ljava/lang/String;[Ljava/lang/String;)[[Ljava/lang/String;"),
};
-int register_libcore_icu_TimeZones(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/icu/TimeZones", gMethods, NELEM(gMethods));
+void register_libcore_icu_TimeZones(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/icu/TimeZones", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
index d3fdabf..1b888be 100644
--- a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
+++ b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
@@ -30,7 +30,7 @@
NATIVE_METHOD(AsynchronousCloseMonitor, signalBlockedThreads, "(Ljava/io/FileDescriptor;)V"),
};
-int register_libcore_io_AsynchronousCloseMonitor(JNIEnv* env) {
+void register_libcore_io_AsynchronousCloseMonitor(JNIEnv* env) {
AsynchronousSocketCloseMonitor::init();
- return jniRegisterNativeMethods(env, "libcore/io/AsynchronousCloseMonitor", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "libcore/io/AsynchronousCloseMonitor", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_io_Memory.cpp b/luni/src/main/native/libcore_io_Memory.cpp
index a511978..bffb4a5 100644
--- a/luni/src/main/native/libcore_io_Memory.cpp
+++ b/luni/src/main/native/libcore_io_Memory.cpp
@@ -398,6 +398,6 @@
NATIVE_METHOD(Memory, unsafeBulkGet, "(Ljava/lang/Object;II[BIIZ)V"),
NATIVE_METHOD(Memory, unsafeBulkPut, "([BIILjava/lang/Object;IIZ)V"),
};
-int register_libcore_io_Memory(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/io/Memory", gMethods, NELEM(gMethods));
+void register_libcore_io_Memory(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/io/Memory", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_io_OsConstants.cpp b/luni/src/main/native/libcore_io_OsConstants.cpp
index c432973..a1cfcf0 100644
--- a/luni/src/main/native/libcore_io_OsConstants.cpp
+++ b/luni/src/main/native/libcore_io_OsConstants.cpp
@@ -447,6 +447,6 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(OsConstants, initConstants, "()V"),
};
-int register_libcore_io_OsConstants(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/io/OsConstants", gMethods, NELEM(gMethods));
+void register_libcore_io_OsConstants(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/io/OsConstants", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index a90c593..30ca145 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -137,9 +137,12 @@
}
static void throwGaiException(JNIEnv* env, const char* functionName, int error) {
- if (error == EAI_SYSTEM) {
- // EAI_SYSTEM means "look at errno instead", so we want our GaiException to have the
- // relevant ErrnoException as its cause.
+ if (errno != 0) {
+ // EAI_SYSTEM should mean "look at errno instead", but both glibc and bionic seem to
+ // mess this up. In particular, if you don't have INTERNET permission, errno will be EACCES
+ // but you'll get EAI_NONAME or EAI_NODATA. So we want our GaiException to have a
+ // potentially-relevant ErrnoException as its cause even if error != EAI_SYSTEM.
+ // http://code.google.com/p/android/issues/detail?id=15722
throwErrnoException(env, functionName);
// Deliberately fall through to throw another exception...
}
@@ -553,6 +556,7 @@
hints.ai_protocol = env->GetIntField(javaHints, protocolFid);
addrinfo* addressList = NULL;
+ errno = 0;
int rc = getaddrinfo(node.c_str(), NULL, &hints, &addressList);
UniquePtr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
if (rc != 0) {
@@ -566,7 +570,7 @@
if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
++addressCount;
} else {
- LOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+ ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
}
}
if (addressCount == 0) {
@@ -584,7 +588,7 @@
for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
// Unknown address family. Skip this address.
- LOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+ ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
continue;
}
@@ -631,6 +635,7 @@
// then remove this hack.
socklen_t size = (ss.ss_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN.
+ errno = 0;
int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), size, buf, sizeof(buf), NULL, 0, flags);
if (rc != 0) {
throwGaiException(env, "getnameinfo", rc);
@@ -908,7 +913,16 @@
++count;
}
- int rc = TEMP_FAILURE_RETRY(poll(fds.get(), count, timeoutMs));
+ // Since we don't know which fds -- if any -- are sockets, be conservative and register
+ // all fds for asynchronous socket close monitoring.
+ std::vector<AsynchronousSocketCloseMonitor*> monitors;
+ for (size_t i = 0; i < count; ++i) {
+ monitors.push_back(new AsynchronousSocketCloseMonitor(fds[i].fd));
+ }
+ int rc = poll(fds.get(), count, timeoutMs);
+ for (size_t i = 0; i < monitors.size(); ++i) {
+ delete monitors[i];
+ }
if (rc == -1) {
throwErrnoException(env, "poll");
return -1;
@@ -1304,6 +1318,6 @@
NATIVE_METHOD(Posix, writeBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
NATIVE_METHOD(Posix, writev, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
};
-int register_libcore_io_Posix(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods));
+void register_libcore_io_Posix(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_net_RawSocket.cpp b/luni/src/main/native/libcore_net_RawSocket.cpp
index a4398f4..4e5059f 100644
--- a/luni/src/main/native/libcore_net_RawSocket.cpp
+++ b/luni/src/main/native/libcore_net_RawSocket.cpp
@@ -53,37 +53,36 @@
* setBlocking() method followed by polymorphic bind().
*/
static void RawSocket_create(JNIEnv* env, jclass, jobject fileDescriptor,
- jstring interfaceName) {
+ jshort protocolType, jstring interfaceName)
+{
ScopedUtfChars ifname(env, interfaceName);
if (ifname.c_str() == NULL) {
return;
}
- short protocol = ETH_P_IP;
- sockunion su;
memset(&su, 0, sizeof(su));
su.sll.sll_family = PF_PACKET;
- su.sll.sll_protocol = htons(protocol);
+ su.sll.sll_protocol = htons(protocolType);
su.sll.sll_ifindex = if_nametoindex(ifname.c_str());
+ int sock = socket(PF_PACKET, SOCK_DGRAM, htons(protocolType));
- int sock = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
if (sock == -1) {
- LOGE("Can't create socket %s", strerror(errno));
+ ALOGE("Can't create socket %s", strerror(errno));
jniThrowSocketException(env, errno);
return;
}
jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
if (!setBlocking(sock, false)) {
- LOGE("Can't set non-blocking mode on socket %s", strerror(errno));
+ ALOGE("Can't set non-blocking mode on socket %s", strerror(errno));
jniThrowSocketException(env, errno);
return;
}
int err = bind(sock, &su.sa, sizeof(su));
if (err != 0) {
- LOGE("Socket bind error %s", strerror(errno));
+ ALOGE("Socket bind error %s", strerror(errno));
jniThrowSocketException(env, errno);
return;
}
@@ -96,8 +95,8 @@
* Assumes that the caller has validated the offset & byteCount values.
*/
static int RawSocket_sendPacket(JNIEnv* env, jclass, jobject fileDescriptor,
- jstring interfaceName, jbyteArray destMac, jbyteArray packet, jint offset,
- jint byteCount)
+ jstring interfaceName, jshort protocolType, jbyteArray destMac,
+ jbyteArray packet, jint offset, jint byteCount)
{
NetFd fd(env, fileDescriptor);
@@ -120,14 +119,12 @@
return 0;
}
- short protocol = ETH_P_IP;
- sockunion su;
memset(&su, 0, sizeof(su));
su.sll.sll_hatype = htons(1); // ARPHRD_ETHER
su.sll.sll_halen = mac.size();
memcpy(&su.sll.sll_addr, mac.get(), mac.size());
su.sll.sll_family = AF_PACKET;
- su.sll.sll_protocol = htons(protocol);
+ su.sll.sll_protocol = htons(protocolType);
su.sll.sll_ifindex = if_nametoindex(ifname.c_str());
int err;
@@ -185,31 +182,33 @@
return 0;
}
- // quick check for UDP type & UDP port
- // the packet is an IP header, UDP header, and UDP payload
- if ((size < (sizeof(iphdr) + sizeof(udphdr)))) {
- return 0; // runt packet
- }
+ if (port != -1) {
+ // quick check for UDP type & UDP port
+ // the packet is an IP header, UDP header, and UDP payload
+ if ((size < (sizeof(struct iphdr) + sizeof(struct udphdr)))) {
+ return 0; // runt packet
+ }
- u_int8_t ip_proto = ((iphdr *) packetData)->protocol;
- if (ip_proto != IPPROTO_UDP) {
- return 0; // something other than UDP
- }
+ u_int8_t ip_proto = ((iphdr *) packetData)->protocol;
+ if (ip_proto != IPPROTO_UDP) {
+ return 0; // something other than UDP
+ }
- __be16 destPort = htons((reinterpret_cast<udphdr*>(packetData + sizeof(iphdr)))->dest);
- if (destPort != port) {
- return 0; // something other than requested port
+ __be16 destPort = htons((reinterpret_cast<udphdr*>(packetData + sizeof(iphdr)))->dest);
+ if (destPort != port) {
+ return 0; // something other than requested port
+ }
}
return size;
}
static JNINativeMethod gRawMethods[] = {
- NATIVE_METHOD(RawSocket, create, "(Ljava/io/FileDescriptor;Ljava/lang/String;)V"),
- NATIVE_METHOD(RawSocket, sendPacket, "(Ljava/io/FileDescriptor;Ljava/lang/String;[B[BII)I"),
+ NATIVE_METHOD(RawSocket, create, "(Ljava/io/FileDescriptor;SLjava/lang/String;)V"),
+ NATIVE_METHOD(RawSocket, sendPacket, "(Ljava/io/FileDescriptor;Ljava/lang/String;S[B[BII)I"),
NATIVE_METHOD(RawSocket, recvPacket, "(Ljava/io/FileDescriptor;[BIIII)I"),
};
-int register_libcore_net_RawSocket(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "libcore/net/RawSocket", gRawMethods, NELEM(gRawMethods));
+void register_libcore_net_RawSocket(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "libcore/net/RawSocket", gRawMethods, NELEM(gRawMethods));
}
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 3f6c1aa..d08b7d2 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -27,7 +27,7 @@
#include "UniquePtr.h"
#include "jni.h"
#include "cutils/log.h"
-#include "cutils/jstring.h" // for strcpylen8to16
+#include "unicode/unistr.h"
#include <string.h>
#include <expat.h>
@@ -410,26 +410,23 @@
* Copies UTF-8 characters into the buffer. Returns the number of Java chars
* which were buffered.
*
- * @param characters to copy into the buffer
- * @param length of characters to copy (in bytes)
* @returns number of UTF-16 characters which were copied
*/
-static size_t fillBuffer(ParsingContext* parsingContext, const char* characters, int length) {
+static size_t fillBuffer(ParsingContext* parsingContext, const char* utf8, int byteCount) {
JNIEnv* env = parsingContext->env;
- // Grow buffer if necessary.
- jcharArray buffer = parsingContext->ensureCapacity(length);
- if (buffer == NULL) return -1;
+ // Grow buffer if necessary (the length in bytes is always >= the length in chars).
+ jcharArray javaChars = parsingContext->ensureCapacity(byteCount);
+ if (javaChars == NULL) return -1;
- // Decode UTF-8 characters into our buffer.
- ScopedCharArrayRW nativeBuffer(env, buffer);
- if (nativeBuffer.get() == NULL) {
+ // Decode UTF-8 characters into our char[].
+ ScopedCharArrayRW chars(env, javaChars);
+ if (chars.get() == NULL) {
return -1;
}
-
- size_t utf16length;
- strcpylen8to16(nativeBuffer.get(), characters, length, &utf16length);
- return utf16length;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString utf16(UnicodeString::fromUTF8(StringPiece(utf8, byteCount)));
+ return utf16.extract(chars.get(), byteCount, status);
}
/**
@@ -1395,13 +1392,7 @@
NATIVE_METHOD(ExpatAttributes, getValueForQName, "(ILjava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ExpatAttributes, getValue, "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
};
-int register_org_apache_harmony_xml_ExpatParser(JNIEnv* env) {
- int result = jniRegisterNativeMethods(env, "org/apache/harmony/xml/ExpatParser",
- parserMethods, NELEM(parserMethods));
- if (result != 0) {
- return result;
- }
-
- return jniRegisterNativeMethods(env, "org/apache/harmony/xml/ExpatAttributes",
- attributeMethods, NELEM(attributeMethods));
+void register_org_apache_harmony_xml_ExpatParser(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "org/apache/harmony/xml/ExpatParser", parserMethods, NELEM(parserMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/xml/ExpatAttributes", attributeMethods, NELEM(attributeMethods));
}
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index 388ead7..687c57e 100644
--- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
+++ b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
@@ -28,6 +28,7 @@
#include <jni.h>
#include <openssl/dsa.h>
+#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
@@ -50,7 +51,7 @@
#ifdef WITH_JNI_TRACE
#define JNI_TRACE(...) \
- ((void)LOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)); \
+ ((void)ALOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)); \
/*
((void)printf("I/" LOG_TAG "-jni:")); \
((void)printf(__VA_ARGS__)); \
@@ -104,6 +105,13 @@
};
typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX;
+struct EVP_CIPHER_CTX_Delete {
+ void operator()(EVP_CIPHER_CTX* p) const {
+ EVP_CIPHER_CTX_cleanup(p);
+ }
+};
+typedef UniquePtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_Delete> Unique_EVP_CIPHER_CTX;
+
struct EVP_PKEY_Delete {
void operator()(EVP_PKEY* p) const {
EVP_PKEY_free(p);
@@ -301,7 +309,7 @@
if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
// problem with asprintf, just throw argument message, log everything
throwSSLExceptionStr(env, message);
- LOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
+ ALOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr);
freeOpenSslErrorState();
return;
}
@@ -359,7 +367,7 @@
throwSSLExceptionStr(env, allocStr);
}
- LOGV("%s", allocStr);
+ ALOGV("%s", allocStr);
free(allocStr);
freeOpenSslErrorState();
}
@@ -407,21 +415,65 @@
/**
* Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the
- * fly.
+ * fly. Returns true on success. If the return value is false, there is a
+ * pending exception.
*/
-static BIGNUM* arrayToBignum(JNIEnv* env, jbyteArray source) {
- JNI_TRACE("arrayToBignum(%p)", source);
+static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) {
+ JNI_TRACE("arrayToBignum(%p, %p)", source, *dest);
ScopedByteArrayRO sourceBytes(env, source);
if (sourceBytes.get() == NULL) {
JNI_TRACE("arrayToBignum(%p) => NULL", source);
- return NULL;
+ return false;
}
- BIGNUM* bn = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()),
+ *dest = BN_bin2bn(reinterpret_cast<const unsigned char*>(sourceBytes.get()),
sourceBytes.size(),
NULL);
- JNI_TRACE("arrayToBignum(%p) => %p", source, bn);
- return bn;
+ if (*dest == NULL) {
+ jniThrowRuntimeException(env, "Conversion to BIGNUM failed");
+ JNI_TRACE("arrayToBignum(%p) => threw exception", source);
+ return false;
+ }
+
+ JNI_TRACE("arrayToBignum(%p) => %p", source, *dest);
+ return true;
+}
+
+/**
+ * Converts an OpenSSL BIGNUM to a Java byte[] array.
+ */
+static jbyteArray bignumToArray(JNIEnv* env, BIGNUM* source) {
+ JNI_TRACE("bignumToArray(%p)", source);
+
+ if (source == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return NULL;
+ }
+
+ int len = BN_num_bytes(source) + 1;
+ jbyteArray javaBytes = env->NewByteArray(len);
+ ScopedByteArrayRW bytes(env, javaBytes);
+ if (bytes.get() == NULL) {
+ JNI_TRACE("bignumToArray(%p) => NULL", source);
+ return NULL;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
+
+ // Set the sign for the Java code.
+ if (BN_is_negative(source)) {
+ *tmp = 0xFF;
+ } else {
+ *tmp = 0x00;
+ }
+
+ if (BN_bn2bin(source, tmp + 1) <= 0) {
+ throwExceptionIfNecessary(env, "bignumToArray");
+ return NULL;
+ }
+
+ JNI_TRACE("bignumToArray(%p) => %p", source, javaBytes);
+ return javaBytes;
}
/**
@@ -500,6 +552,94 @@
THREAD_setup();
}
+static void NativeCrypto_ENGINE_load_dynamic(JNIEnv*, jclass) {
+ JNI_TRACE("ENGINE_load_dynamic()");
+
+ ENGINE_load_dynamic();
+}
+
+static jint NativeCrypto_ENGINE_by_id(JNIEnv* env, jclass, jstring idJava) {
+ JNI_TRACE("ENGINE_by_id(%p)", idJava);
+
+ ScopedUtfChars id(env, idJava);
+ if (id.c_str() == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL");
+ return 0;
+ }
+
+ ENGINE* e = ENGINE_by_id(id.c_str());
+ if (e == NULL) {
+ throwExceptionIfNecessary(env, "ENGINE_by_id");
+ return 0;
+ }
+
+ JNI_TRACE("ENGINE_by_id(%p) => %p", idJava, e);
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(e));
+}
+
+static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jint engineRef) {
+ ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
+ JNI_TRACE("ENGINE_init(%p)", e);
+
+ if (e == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
+ return 0;
+ }
+
+ int ret = ENGINE_init(e);
+ JNI_TRACE("ENGINE_init(%p) => %d", e, ret);
+ return ret;
+}
+
+static jint NativeCrypto_ENGINE_finish(JNIEnv* env, jclass, jint engineRef) {
+ ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
+ JNI_TRACE("ENGINE_finish(%p)", e);
+
+ if (e == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
+ return 0;
+ }
+
+ int ret = ENGINE_finish(e);
+ JNI_TRACE("ENGINE_finish(%p) => %d", e, ret);
+ return ret;
+}
+
+static jint NativeCrypto_ENGINE_free(JNIEnv* env, jclass, jint engineRef) {
+ ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
+ JNI_TRACE("ENGINE_free(%p)", e);
+
+ if (e == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0");
+ return 0;
+ }
+
+ int ret = ENGINE_free(e);
+ JNI_TRACE("ENGINE_free(%p) => %d", e, ret);
+ return ret;
+}
+
+static jint NativeCrypto_ENGINE_load_private_key(JNIEnv* env, jclass, jint engineRef,
+ jstring idJava) {
+ ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef));
+ JNI_TRACE("ENGINE_load_private_key(%p, %p)", e, idJava);
+
+ ScopedUtfChars id(env, idJava);
+ if (id.c_str() == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL");
+ return 0;
+ }
+
+ Unique_EVP_PKEY pkey(ENGINE_load_private_key(e, id.c_str(), NULL, NULL));
+ if (pkey.get() == NULL) {
+ throwExceptionIfNecessary(env, "ENGINE_load_private_key");
+ return 0;
+ }
+
+ JNI_TRACE("ENGINE_load_private_key(%p, %p) => %p", e, idJava, pkey.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
/**
* public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g,
* byte[] pub_key, byte[] priv_key);
@@ -516,16 +656,28 @@
return NULL;
}
- dsa->p = arrayToBignum(env, p);
- dsa->q = arrayToBignum(env, q);
- dsa->g = arrayToBignum(env, g);
- dsa->pub_key = arrayToBignum(env, pub_key);
-
- if (priv_key != NULL) {
- dsa->priv_key = arrayToBignum(env, priv_key);
+ if (!arrayToBignum(env, p, &dsa->p)) {
+ return NULL;
}
- if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL || dsa->pub_key == NULL) {
+ if (!arrayToBignum(env, q, &dsa->q)) {
+ return NULL;
+ }
+
+ if (!arrayToBignum(env, g, &dsa->g)) {
+ return NULL;
+ }
+
+ if (pub_key != NULL && !arrayToBignum(env, pub_key, &dsa->pub_key)) {
+ return NULL;
+ }
+
+ if (priv_key != NULL && !arrayToBignum(env, priv_key, &dsa->priv_key)) {
+ return NULL;
+ }
+
+ if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL
+ || (dsa->pub_key == NULL && dsa->priv_key == NULL)) {
jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
return NULL;
}
@@ -548,30 +700,56 @@
/**
* private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q);
*/
-static EVP_PKEY* NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass,
+static jint NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass,
jbyteArray n, jbyteArray e, jbyteArray d,
- jbyteArray p, jbyteArray q) {
- JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p)", n, e, d, p, q);
+ jbyteArray p, jbyteArray q,
+ jbyteArray dmp1, jbyteArray dmq1,
+ jbyteArray iqmp) {
+ JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, iqmp=%p)",
+ n, e, d, p, q, dmp1, dmq1, iqmp);
Unique_RSA rsa(RSA_new());
if (rsa.get() == NULL) {
jniThrowRuntimeException(env, "RSA_new failed");
- return NULL;
+ return 0;
}
- rsa->n = arrayToBignum(env, n);
- rsa->e = arrayToBignum(env, e);
-
- if (d != NULL) {
- rsa->d = arrayToBignum(env, d);
+ if (e == NULL && d == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "e == NULL && d == NULL");
+ JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == NULL && d == NULL");
+ return 0;
}
- if (p != NULL) {
- rsa->p = arrayToBignum(env, p);
+ if (!arrayToBignum(env, n, &rsa->n)) {
+ return 0;
}
- if (q != NULL) {
- rsa->q = arrayToBignum(env, q);
+ if (e != NULL && !arrayToBignum(env, e, &rsa->e)) {
+ return 0;
+ }
+
+ if (d != NULL && !arrayToBignum(env, d, &rsa->d)) {
+ return 0;
+ }
+
+ if (p != NULL && !arrayToBignum(env, p, &rsa->p)) {
+ return 0;
+ }
+
+ if (q != NULL && !arrayToBignum(env, q, &rsa->q)) {
+ return 0;
+ }
+
+ if (dmp1 != NULL && !arrayToBignum(env, dmp1, &rsa->dmp1)) {
+ return 0;
+ }
+
+ if (dmq1 != NULL && !arrayToBignum(env, dmq1, &rsa->dmq1)) {
+ return 0;
+ }
+
+ if (iqmp != NULL && !arrayToBignum(env, iqmp, &rsa->iqmp)) {
+ return 0;
}
#ifdef WITH_JNI_TRACE
@@ -581,23 +759,73 @@
}
#endif
- if (rsa->n == NULL || rsa->e == NULL) {
+ if (rsa->n == NULL || (rsa->e == NULL && rsa->d == NULL)) {
jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
- return NULL;
+ return 0;
+ }
+
+ /*
+ * If the private exponent is available, there is the potential to do signing
+ * operations. If the public exponent is also available, OpenSSL will do RSA
+ * blinding. Enable it if possible.
+ */
+ if (rsa->d != NULL) {
+ if (rsa->e != NULL) {
+ JNI_TRACE("EVP_PKEY_new_RSA(...) enabling RSA blinding => %p", rsa.get());
+ RSA_blinding_on(rsa.get(), NULL);
+ } else {
+ JNI_TRACE("EVP_PKEY_new_RSA(...) disabling RSA blinding => %p", rsa.get());
+ RSA_blinding_off(rsa.get());
+ }
}
Unique_EVP_PKEY pkey(EVP_PKEY_new());
if (pkey.get() == NULL) {
jniThrowRuntimeException(env, "EVP_PKEY_new failed");
- return NULL;
+ return 0;
}
if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
jniThrowRuntimeException(env, "EVP_PKEY_new failed");
- return NULL;
+ return 0;
}
OWNERSHIP_TRANSFERRED(rsa);
- JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p) => %p", n, e, d, p, q, pkey.get());
- return pkey.release();
+ JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, iqmp=%p) => %p",
+ n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
+/**
+ * private static native int EVP_PKEY_size(int pkey);
+ */
+static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("EVP_PKEY_type(%p)", pkey);
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return -1;
+ }
+
+ int result = EVP_PKEY_type(pkey->type);
+ JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result);
+ return result;
+}
+
+/**
+ * private static native int EVP_PKEY_size(int pkey);
+ */
+static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("EVP_PKEY_size(%p)", pkey);
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return -1;
+ }
+
+ int result = EVP_PKEY_size(pkey);
+ JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result);
+ return result;
}
/**
@@ -612,6 +840,425 @@
}
/*
+ * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[])
+ */
+static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey);
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return NULL;
+ }
+
+ Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey));
+ if (pkcs8.get() == NULL) {
+ throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO");
+ JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey);
+ return NULL;
+ }
+
+ int len = i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), NULL);
+ if (len < 0) {
+ throwExceptionIfNecessary(env, "i2d_PKCS8_PRIV_KEY_INFO");
+ return NULL;
+ }
+
+ jbyteArray javaBytes = env->NewByteArray(len);
+ ScopedByteArrayRW bytes(env, javaBytes);
+ if (bytes.get() == NULL) {
+ return NULL;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
+ if (i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), &tmp) < 0) {
+ throwExceptionIfNecessary(env, "i2d_PKCS8_PRIV_KEY_INFO");
+ return NULL;
+ }
+
+ JNI_TRACE("pkey=%p i2d_PKCS8_PRIV_KEY_INFO => size=%d", pkey, len);
+ return javaBytes;
+}
+
+/*
+ * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[])
+ */
+static jint NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+ JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes);
+
+ ScopedByteArrayRO bytes(env, keyJavaBytes);
+ if (bytes.get() == NULL) {
+ JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes);
+ return 0;
+ }
+
+ const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
+ Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, bytes.size()));
+ if (pkcs8.get() == NULL) {
+ throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
+ JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes);
+ return 0;
+ }
+
+ Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
+ if (pkey.get() == NULL) {
+ throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO");
+ JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes);
+ return 0;
+ }
+
+ JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
+/*
+ * static native byte[] i2d_PUBKEY(int)
+ */
+static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("i2d_PUBKEY(%p)", pkey);
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return NULL;
+ }
+
+ int len = i2d_PUBKEY(pkey, NULL);
+ if (len < 0) {
+ throwExceptionIfNecessary(env, "i2d_PUBKEY");
+ JNI_TRACE("i2d_PUBKEY(%p) => threw error measuring key", pkey);
+ return NULL;
+ }
+
+ jbyteArray javaBytes = env->NewByteArray(len);
+ ScopedByteArrayRW bytes(env, javaBytes);
+ if (bytes.get() == NULL) {
+ return NULL;
+ }
+
+ unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get());
+ if (i2d_PUBKEY(pkey, &tmp) < 0) {
+ throwExceptionIfNecessary(env, "i2d_PUBKEY");
+ JNI_TRACE("i2d_PUBKEY(%p) => threw error converting key", pkey);
+ return NULL;
+ }
+
+ JNI_TRACE("pkey=%p i2d_PUBKEY => size=%d", pkey, len);
+ return javaBytes;
+}
+
+/*
+ * static native int d2i_PUBKEY(byte[])
+ */
+static jint NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) {
+ JNI_TRACE("d2i_PUBKEY(%p)", javaBytes);
+
+ ScopedByteArrayRO bytes(env, javaBytes);
+ if (bytes.get() == NULL) {
+ JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes);
+ return 0;
+ }
+
+ const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get());
+ Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, bytes.size()));
+ if (pkey.get() == NULL) {
+ JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes);
+ throwExceptionIfNecessary(env, "d2i_PUBKEY");
+ return 0;
+ }
+
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
+/*
+ * public static native int RSA_generate_key(int modulusBits, byte[] publicExponent);
+ */
+static jint NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits,
+ jbyteArray publicExponent) {
+ JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent);
+
+ BIGNUM* eRef;
+ if (!arrayToBignum(env, publicExponent, &eRef)) {
+ return 0;
+ }
+ Unique_BIGNUM e(eRef);
+
+ Unique_RSA rsa(RSA_new());
+ if (rsa.get() == NULL) {
+ jniThrowOutOfMemoryError(env, "Unable to allocate RSA key");
+ return 0;
+ }
+
+ if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), NULL) < 0) {
+ throwExceptionIfNecessary(env, "RSA_generate_key_ex");
+ return 0;
+ }
+
+ Unique_EVP_PKEY pkey(EVP_PKEY_new());
+ if (pkey.get() == NULL) {
+ jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
+ return 0;
+ }
+
+ if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
+ jniThrowRuntimeException(env, "RSA_generate_key_ex failed");
+ return 0;
+ }
+
+ OWNERSHIP_TRANSFERRED(rsa);
+ JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
+/*
+ * public static native byte[][] get_RSA_public_params(int);
+ */
+static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("get_RSA_public_params(%p)", pkey);
+
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == NULL) {
+ jniThrowRuntimeException(env, "get_RSA_public_params failed");
+ return 0;
+ }
+
+ jobjectArray joa = env->NewObjectArray(2, JniConstants::byteArrayClass, NULL);
+ if (joa == NULL) {
+ return NULL;
+ }
+
+ jbyteArray n = bignumToArray(env, rsa->n);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 0, n);
+
+ jbyteArray e = bignumToArray(env, rsa->e);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 1, e);
+
+ return joa;
+}
+
+/*
+ * public static native byte[][] get_RSA_private_params(int);
+ */
+static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("get_RSA_public_params(%p)", pkey);
+
+ Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == NULL) {
+ jniThrowRuntimeException(env, "get_RSA_public_params failed");
+ return 0;
+ }
+
+ jobjectArray joa = env->NewObjectArray(8, JniConstants::byteArrayClass, NULL);
+ if (joa == NULL) {
+ return NULL;
+ }
+
+ jbyteArray n = bignumToArray(env, rsa->n);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 0, n);
+
+ if (rsa->e != NULL) {
+ jbyteArray e = bignumToArray(env, rsa->e);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 1, e);
+ }
+
+ if (rsa->d != NULL) {
+ jbyteArray d = bignumToArray(env, rsa->d);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 2, d);
+ }
+
+ if (rsa->p != NULL) {
+ jbyteArray p = bignumToArray(env, rsa->p);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 3, p);
+ }
+
+ if (rsa->q != NULL) {
+ jbyteArray q = bignumToArray(env, rsa->q);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 4, q);
+ }
+
+ if (rsa->dmp1 != NULL) {
+ jbyteArray dmp1 = bignumToArray(env, rsa->dmp1);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 5, dmp1);
+ }
+
+ if (rsa->dmq1 != NULL) {
+ jbyteArray dmq1 = bignumToArray(env, rsa->dmq1);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 6, dmq1);
+ }
+
+ if (rsa->iqmp != NULL) {
+ jbyteArray iqmp = bignumToArray(env, rsa->iqmp);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 7, iqmp);
+ }
+
+ return joa;
+}
+
+/*
+ * public static native int DSA_generate_key(int, byte[]);
+ */
+static jint NativeCrypto_DSA_generate_key(JNIEnv* env, jclass, jint primeBits,
+ jbyteArray seedJavaBytes, jbyteArray gBytes, jbyteArray pBytes, jbyteArray qBytes) {
+ JNI_TRACE("DSA_generate_key(%d, %p, %p, %p, %p)", primeBits, seedJavaBytes,
+ gBytes, pBytes, qBytes);
+
+ UniquePtr<unsigned char[]> seedPtr;
+ unsigned long seedSize = 0;
+ if (seedJavaBytes != NULL) {
+ ScopedByteArrayRO seed(env, seedJavaBytes);
+ if (seed.get() == NULL) {
+ return 0;
+ }
+
+ seedSize = seed.size();
+ seedPtr.reset(new unsigned char[seedSize]);
+
+ memcpy(seedPtr.get(), seed.get(), seedSize);
+ }
+
+ Unique_DSA dsa(DSA_new());
+ if (dsa.get() == NULL) {
+ JNI_TRACE("DSA_generate_key failed");
+ jniThrowOutOfMemoryError(env, "Unable to allocate DSA key");
+ return 0;
+ }
+
+ if (gBytes != NULL && pBytes != NULL && qBytes != NULL) {
+ JNI_TRACE("DSA_generate_key parameters specified");
+
+ if (!arrayToBignum(env, gBytes, &dsa->g)) {
+ return 0;
+ }
+
+ if (!arrayToBignum(env, pBytes, &dsa->p)) {
+ return 0;
+ }
+
+ if (!arrayToBignum(env, qBytes, &dsa->q)) {
+ return 0;
+ }
+ } else {
+ JNI_TRACE("DSA_generate_key generating parameters");
+
+ if (!DSA_generate_parameters_ex(dsa.get(), primeBits, seedPtr.get(), seedSize, NULL, NULL, NULL)) {
+ JNI_TRACE("DSA_generate_key => param generation failed");
+ throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_parameters_ex failed");
+ return 0;
+ }
+ }
+
+ if (!DSA_generate_key(dsa.get())) {
+ JNI_TRACE("DSA_generate_key failed");
+ throwExceptionIfNecessary(env, "NativeCrypto_DSA_generate_key failed");
+ return 0;
+ }
+
+ Unique_EVP_PKEY pkey(EVP_PKEY_new());
+ if (pkey.get() == NULL) {
+ JNI_TRACE("DSA_generate_key failed");
+ jniThrowRuntimeException(env, "NativeCrypto_DSA_generate_key failed");
+ return 0;
+ }
+
+ if (EVP_PKEY_assign_DSA(pkey.get(), dsa.get()) != 1) {
+ JNI_TRACE("DSA_generate_key failed");
+ jniThrowRuntimeException(env, "NativeCrypto_DSA_generate_key failed");
+ return 0;
+ }
+
+ OWNERSHIP_TRANSFERRED(dsa);
+ JNI_TRACE("DSA_generate_key(n=%d, e=%p) => %p", primeBits, seedPtr.get(), pkey.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(pkey.release()));
+}
+
+/*
+ * public static native byte[][] get_DSA_params(int);
+ */
+static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jint pkeyRef) {
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("get_DSA_params(%p)", pkey);
+
+ Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey));
+ if (dsa.get() == NULL) {
+ jniThrowRuntimeException(env, "get_DSA_params failed");
+ return 0;
+ }
+
+ jobjectArray joa = env->NewObjectArray(5, JniConstants::byteArrayClass, NULL);
+ if (joa == NULL) {
+ return NULL;
+ }
+
+ jbyteArray g = bignumToArray(env, dsa->g);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 0, g);
+
+ jbyteArray p = bignumToArray(env, dsa->p);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 1, p);
+
+ jbyteArray q = bignumToArray(env, dsa->q);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 2, q);
+
+ if (dsa->pub_key != NULL) {
+ jbyteArray pub_key = bignumToArray(env, dsa->pub_key);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 3, pub_key);
+ }
+
+ if (dsa->priv_key != NULL) {
+ jbyteArray priv_key = bignumToArray(env, dsa->priv_key);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, 4, priv_key);
+ }
+
+ return joa;
+}
+
+/*
* public static native void EVP_MD_CTX_destroy(int)
*/
static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, EVP_MD_CTX* ctx) {
@@ -632,11 +1279,13 @@
jniThrowNullPointerException(env, NULL);
return 0;
}
+
EVP_MD_CTX* copy = EVP_MD_CTX_create();
if (copy == NULL) {
jniThrowOutOfMemoryError(env, "Unable to allocate copy of EVP_MD_CTX");
return 0;
}
+
EVP_MD_CTX_init(copy);
int result = EVP_MD_CTX_copy_ex(copy, ctx);
if (result == 0) {
@@ -644,15 +1293,17 @@
jniThrowRuntimeException(env, "Unable to copy EVP_MD_CTX");
return 0;
}
+
JNI_TRACE("NativeCrypto_EVP_MD_CTX_copy(%p) => %p", ctx, copy);
- return (jint) copy;
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(copy));
}
/*
* public static native int EVP_DigestFinal(int, byte[], int)
*/
-static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
+static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, jint ctxRef,
jbyteArray hash, jint offset) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
JNI_TRACE("NativeCrypto_EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset);
if (ctx == NULL || hash == NULL) {
@@ -680,7 +1331,8 @@
/*
* public static native int EVP_DigestInit(int)
*/
-static int NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, EVP_MD* evp_md) {
+static jint NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, jint evpMdRef) {
+ EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef);
JNI_TRACE("NativeCrypto_EVP_DigestInit(%p)", evp_md);
if (evp_md == NULL) {
@@ -702,7 +1354,7 @@
return 0;
}
}
- return (jint) ctx.release();
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(ctx.release()));
}
/*
@@ -729,7 +1381,7 @@
}
JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => %p", algorithmChars.c_str(), evp_md);
- return (jint) evp_md;
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(evp_md));
}
/*
@@ -767,8 +1419,9 @@
/*
* public static native void EVP_DigestUpdate(int, byte[], int, int)
*/
-static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
+static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, jint ctxRef,
jbyteArray buffer, jint offset, jint length) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
JNI_TRACE("NativeCrypto_EVP_DigestUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
if (offset < 0 || length < 0) {
@@ -794,6 +1447,103 @@
}
/*
+ * public static native int EVP_SignInit(java.lang.String)
+ */
+static jint NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jstring algorithm) {
+ JNI_TRACE("NativeCrypto_EVP_SignInit(%p)", algorithm);
+
+ if (algorithm == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return 0;
+ }
+
+ Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create());
+ if (ctx.get() == NULL) {
+ jniThrowOutOfMemoryError(env, "Unable to allocate EVP_MD_CTX");
+ return 0;
+ }
+ JNI_TRACE("NativeCrypto_EVP_SignInit ctx=%p", ctx.get());
+
+ ScopedUtfChars algorithmChars(env, algorithm);
+ if (algorithmChars.c_str() == NULL) {
+ return 0;
+ }
+ JNI_TRACE("NativeCrypto_EVP_SignInit algorithmChars=%s", algorithmChars.c_str());
+
+ const EVP_MD* digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str()));
+ if (digest == NULL) {
+ jniThrowRuntimeException(env, "Hash algorithm not found");
+ return 0;
+ }
+
+ int ok = EVP_SignInit(ctx.get(), digest);
+ if (ok == 0) {
+ bool exception = throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignInit");
+ if (exception) {
+ return 0;
+ }
+ }
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(ctx.release()));
+}
+
+/*
+ * public static native void EVP_SignUpdate(int, byte[], int, int)
+ */
+static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jint ctxRef,
+ jbyteArray buffer, jint offset, jint length) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
+ JNI_TRACE("NativeCrypto_EVP_SignUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
+
+ if (ctx == NULL || buffer == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+
+ ScopedByteArrayRO bufferBytes(env, buffer);
+ if (bufferBytes.get() == NULL) {
+ return;
+ }
+ int ok = EVP_SignUpdate(ctx,
+ reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
+ length);
+ if (ok == 0) {
+ throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignUpdate");
+ }
+}
+
+/*
+ * public static native int EVP_SignFinal(int, byte[], int, int)
+ */
+static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jint ctxRef, jbyteArray signature,
+ jint offset, jint pkeyRef) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctx, signature, offset, pkey);
+
+ if (ctx == NULL || pkey == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return -1;
+ }
+
+ ScopedByteArrayRW signatureBytes(env, signature);
+ if (signatureBytes.get() == NULL) {
+ return -1;
+ }
+ unsigned int bytesWritten = -1;
+ int ok = EVP_SignFinal(ctx,
+ reinterpret_cast<unsigned char*>(signatureBytes.get() + offset),
+ &bytesWritten,
+ pkey);
+ if (ok == 0) {
+ throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal");
+ }
+ JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u",
+ ctx, signature, offset, pkey, bytesWritten);
+
+ return bytesWritten;
+}
+
+/*
* public static native int EVP_VerifyInit(java.lang.String)
*/
static jint NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jstring algorithm) {
@@ -830,14 +1580,15 @@
return 0;
}
}
- return (jint) ctx.release();
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(ctx.release()));
}
/*
* public static native void EVP_VerifyUpdate(int, byte[], int, int)
*/
-static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx,
+static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jint ctxRef,
jbyteArray buffer, jint offset, jint length) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
if (ctx == NULL || buffer == NULL) {
@@ -860,8 +1611,10 @@
/*
* public static native int EVP_VerifyFinal(int, byte[], int, int, int)
*/
-static int NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray buffer,
- jint offset, jint length, EVP_PKEY* pkey) {
+static jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jint ctxRef, jbyteArray buffer,
+ jint offset, jint length, jint pkeyRef) {
+ EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)",
ctx, buffer, offset, length, pkey);
@@ -878,7 +1631,7 @@
reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
length,
pkey);
- if (ok == 0) {
+ if (ok < 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal");
}
JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
@@ -887,8 +1640,173 @@
return ok;
}
+/*
+ * public static native int EVP_get_cipherbyname(java.lang.String)
+ */
+static jint NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) {
+ JNI_TRACE("EVP_get_cipherbyname(%p)", algorithm);
+ if (algorithm == NULL) {
+ JNI_TRACE("EVP_get_cipherbyname(%p) => threw exception algorithm == null", algorithm);
+ jniThrowNullPointerException(env, NULL);
+ return -1;
+ }
+
+ ScopedUtfChars algorithmChars(env, algorithm);
+ if (algorithmChars.c_str() == NULL) {
+ return 0;
+ }
+ JNI_TRACE("EVP_get_cipherbyname(%p) => algorithm = %s", algorithm, algorithmChars.c_str());
+
+ const EVP_CIPHER* evp_cipher = EVP_get_cipherbyname(algorithmChars.c_str());
+ if (evp_cipher == NULL) {
+ jniThrowRuntimeException(env, "Cipher algorithm not found");
+ return 0;
+ }
+
+ JNI_TRACE("EVP_get_cipherbyname(%s) => %p", algorithmChars.c_str(), evp_cipher);
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(evp_cipher));
+}
+
+/*
+ * public static native int EVP_CipherInit_ex(int cipherNid, byte[] key, byte[] iv,
+ * boolean encrypting);
+ */
+static jint NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jint cipherRef, jbyteArray keyArray,
+ jbyteArray ivArray, jboolean encrypting) {
+ const EVP_CIPHER* evp_cipher = reinterpret_cast<const EVP_CIPHER*>(cipherRef);
+ JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %d)", evp_cipher, keyArray, ivArray, encrypting ? 1 : 0);
+
+ ScopedByteArrayRO keyBytes(env, keyArray);
+ if (keyBytes.get() == NULL) {
+ return 0;
+ }
+
+ // The IV can be null if we're using ECB.
+ UniquePtr<unsigned char[]> ivPtr;
+ if (ivArray != NULL) {
+ ScopedByteArrayRO ivBytes(env, ivArray);
+ if (ivBytes.get() == NULL) {
+ return 0;
+ }
+
+ ivPtr.reset(new unsigned char[ivBytes.size()]);
+ memcpy(ivPtr.get(), ivBytes.get(), ivBytes.size());
+ }
+
+ Unique_EVP_CIPHER_CTX ctx(EVP_CIPHER_CTX_new());
+ if (ctx.get() == NULL) {
+ jniThrowOutOfMemoryError(env, "Unable to allocate cipher context");
+ JNI_TRACE("ctx=%p EVP_CipherInit_ex => context allocation error", evp_cipher);
+ return 0;
+ }
+
+ const unsigned char* key = reinterpret_cast<const unsigned char*>(keyBytes.get());
+ if (!EVP_CipherInit_ex(ctx.get(), evp_cipher, NULL, key, ivPtr.get(), encrypting ? 1 : 0)) {
+ throwExceptionIfNecessary(env, "EVP_CipherInit_ex");
+ JNI_TRACE("EVP_CipherInit_ex => error initializing cipher");
+ return 0;
+ }
+
+ JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %d) => %p", evp_cipher, keyArray, ivArray,
+ encrypting ? 1 : 0, ctx.get());
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(ctx.release()));
+}
+
+/*
+ * public static native int EVP_CipherUpdate(int ctx, byte[] out, int outOffset, byte[] in,
+ * int inOffset);
+ */
+static jint NativeCrypto_EVP_CipherUpdate(JNIEnv* env, jclass, jint ctxRef, jbyteArray outArray,
+ jint outOffset, jbyteArray inArray, jint inOffset) {
+ EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
+ JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d)", ctx, outArray, outOffset, inArray, inOffset);
+
+ if (ctx == NULL) {
+ jniThrowNullPointerException(env, "ctx == null");
+ JNI_TRACE("ctx=%p EVP_CipherUpdate => ctx == null", ctx);
+ return 0;
+ }
+
+ ScopedByteArrayRO inBytes(env, inArray);
+ if (inBytes.get() == NULL) {
+ return 0;
+ }
+ const size_t inSize = inBytes.size();
+ if (size_t(inOffset + EVP_CIPHER_CTX_block_size(ctx)) > inSize) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
+ return 0;
+ }
+
+ ScopedByteArrayRW outBytes(env, outArray);
+ if (outBytes.get() == NULL) {
+ return 0;
+ }
+ const size_t outSize = outBytes.size();
+ if (size_t(outOffset + EVP_CIPHER_CTX_block_size(ctx)) > outSize) {
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
+ return 0;
+ }
+
+ unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
+ const unsigned char* in = reinterpret_cast<const unsigned char*>(inBytes.get());
+
+ int outl;
+ if (!EVP_CipherUpdate(ctx, out + outOffset, &outl, in+inOffset, inSize - inOffset)) {
+ throwExceptionIfNecessary(env, "EVP_CipherInit_ex");
+ JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx);
+ return 0;
+ }
+
+ JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d) => %d", ctx, outArray, outOffset, inArray,
+ inOffset, outl);
+ return outl;
+}
+
+/*
+ * public static native int EVP_CipherFinal(int ctx, byte[] out, int outOffset);
+ */
+static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jint ctxRef, jbyteArray outArray,
+ jint outOffset) {
+ EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
+ JNI_TRACE("EVP_CipherFinal_ex(%p, %p, %d)", ctx, outArray, outOffset);
+
+ if (ctx == NULL) {
+ jniThrowNullPointerException(env, "ctx == null");
+ JNI_TRACE("ctx=%p EVP_CipherFinal_ex => ctx == null", ctx);
+ return 0;
+ }
+
+ ScopedByteArrayRW outBytes(env, outArray);
+ if (outBytes.get() == NULL) {
+ return 0;
+ }
+
+ unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get());
+
+ int outl;
+ if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) {
+ throwExceptionIfNecessary(env, "EVP_CipherInit_ex");
+ JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx);
+ return 0;
+ }
+
+ JNI_TRACE("EVP_CipherFinal(%p, %p, %d) => %d", ctx, outArray, outOffset, outl);
+ return outl;
+}
+
+/*
+ * public static native void EVP_CIPHER_CTX_cleanup(int ctx);
+ */
+static void NativeCrypto_EVP_CIPHER_CTX_cleanup(JNIEnv*, jclass, jint ctxRef) {
+ EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef);
+
+ if (ctx != NULL) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ }
+}
+
/**
- * Verifies an RSA signature.
+ * public static native void RAND_seed(byte[]);
*/
static void NativeCrypto_RAND_seed(JNIEnv* env, jclass, jbyteArray seed) {
JNI_TRACE("NativeCrypto_RAND_seed seed=%p", seed);
@@ -899,7 +1817,7 @@
RAND_seed(randseed.get(), randseed.size());
}
-static int NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) {
+static jint NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) {
JNI_TRACE("NativeCrypto_RAND_load_file filename=%p max_bytes=%lld", filename, max_bytes);
ScopedUtfChars file(env, filename);
if (file.c_str() == NULL) {
@@ -1109,6 +2027,11 @@
*
* (7) a java.io.FileDescriptor wrapper to check for socket close
*
+ * We store the NPN protocols list so we can either send it (from the server) or
+ * select a protocol (on the client). We eagerly acquire a pointer to the array
+ * data so the callback doesn't need to acquire resources that it cannot
+ * release.
+ *
* Because renegotiation can be requested by the peer at any time,
* care should be taken to maintain an appropriate JNIEnv on any
* downcall to openssl since it could result in an upcall to Java. The
@@ -1134,6 +2057,9 @@
JNIEnv* env;
jobject sslHandshakeCallbacks;
jobject fileDescriptor;
+ jbyteArray npnProtocolsArray;
+ jbyte* npnProtocolsData;
+ size_t npnProtocolsLength;
Unique_RSA ephemeralRsa;
Unique_EC_KEY ephemeralEc;
@@ -1172,6 +2098,9 @@
waitingThreads(0),
env(NULL),
sslHandshakeCallbacks(NULL),
+ npnProtocolsArray(NULL),
+ npnProtocolsData(NULL),
+ npnProtocolsLength(-1),
ephemeralRsa(NULL),
ephemeralEc(NULL) {
fdsEmergency[0] = -1;
@@ -1187,8 +2116,11 @@
* @param env The JNIEnv
* @param shc The SSLHandshakeCallbacks
* @param fd The FileDescriptor
+ * @param npnProtocols NPN protocols so that they may be advertised (by the
+ * server) or selected (by the client). Has no effect
+ * unless NPN is enabled.
*/
- bool setCallbackState(JNIEnv* e, jobject shc, jobject fd) {
+ bool setCallbackState(JNIEnv* e, jobject shc, jobject fd, jbyteArray npnProtocols) {
NetFd netFd(e, fd);
if (netFd.isClosed()) {
return false;
@@ -1196,13 +2128,27 @@
env = e;
sslHandshakeCallbacks = shc;
fileDescriptor = fd;
+ if (npnProtocols != NULL) {
+ npnProtocolsArray = npnProtocols;
+ npnProtocolsLength = e->GetArrayLength(npnProtocols);
+ npnProtocolsData = e->GetByteArrayElements(npnProtocols, NULL);
+ if (npnProtocolsData == NULL) {
+ return false;
+ }
+ }
return true;
}
void clearCallbackState() {
- env = NULL;
sslHandshakeCallbacks = NULL;
fileDescriptor = NULL;
+ if (npnProtocolsArray != NULL) {
+ env->ReleaseByteArrayElements(npnProtocolsArray, npnProtocolsData, JNI_ABORT);
+ npnProtocolsArray = NULL;
+ npnProtocolsData = NULL;
+ npnProtocolsLength = -1;
+ }
+ env = NULL;
}
};
@@ -1221,7 +2167,7 @@
* @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
* @param fdObject The FileDescriptor, since appData->fileDescriptor should be NULL
* @param appData The application data structure with mutex info etc.
- * @param timeout The timeout value for select call, with the special value
+ * @param timeout_millis The timeout value for select call, with the special value
* 0 meaning no timeout at all (wait indefinitely). Note: This is
* the Java semantics of the timeout value, not the usual
* select() semantics.
@@ -1229,7 +2175,7 @@
* THROW_SOCKETEXCEPTION if a SocketException was thrown, -1 on
* additional errors
*/
-static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout) {
+static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout_millis) {
// This loop is an expanded version of the NET_FAILURE_RETRY
// macro. It cannot simply be used in this case because select
// cannot be restarted without recreating the fd_sets and timeout
@@ -1244,8 +2190,8 @@
break;
}
int intFd = fd.get();
- JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout=%d",
- (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout);
+ JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout_millis=%d",
+ (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout_millis);
FD_ZERO(&rfds);
FD_ZERO(&wfds);
@@ -1263,9 +2209,9 @@
// Build a struct for the timeout data if we actually want a timeout.
timeval tv;
timeval* ptv;
- if (timeout > 0) {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = 0;
+ if (timeout_millis > 0) {
+ tv.tv_sec = timeout_millis / 1000;
+ tv.tv_usec = (timeout_millis % 1000) * 1000;
ptv = &tv;
} else {
ptv = NULL;
@@ -1273,9 +2219,9 @@
AsynchronousSocketCloseMonitor monitor(intFd);
result = select(maxFd + 1, &rfds, &wfds, NULL, ptv);
- JNI_TRACE("sslSelect %s fd=%d appData=%p timeout=%d => %d",
+ JNI_TRACE("sslSelect %s fd=%d appData=%p timeout_millis=%d => %d",
(type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE",
- fd.get(), appData, timeout, result);
+ fd.get(), appData, timeout_millis, result);
if (result == -1) {
if (fd.isClosed()) {
result = THROWN_EXCEPTION;
@@ -1353,7 +2299,7 @@
AppData* appData = toAppData(ssl);
JNIEnv* env = appData->env;
if (env == NULL) {
- LOGE("AppData->env missing in cert_verify_callback");
+ ALOGE("AppData->env missing in cert_verify_callback");
JNI_TRACE("ssl=%p cert_verify_callback => 0", ssl);
return 0;
}
@@ -1394,7 +2340,7 @@
AppData* appData = toAppData(ssl);
JNIEnv* env = appData->env;
if (env == NULL) {
- LOGE("AppData->env missing in info_callback");
+ ALOGE("AppData->env missing in info_callback");
JNI_TRACE("ssl=%p info_callback env error", ssl);
return;
}
@@ -1426,12 +2372,12 @@
AppData* appData = toAppData(ssl);
JNIEnv* env = appData->env;
if (env == NULL) {
- LOGE("AppData->env missing in client_cert_cb");
+ ALOGE("AppData->env missing in client_cert_cb");
JNI_TRACE("ssl=%p client_cert_cb env error => 0", ssl);
return 0;
}
if (env->ExceptionCheck()) {
- JNI_TRACE("ssl=%p client_cert_cb already pending exception", ssl);
+ JNI_TRACE("ssl=%p client_cert_cb already pending exception => 0", ssl);
return 0;
}
jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks;
@@ -1452,6 +2398,8 @@
break;
case SSL3_VERSION:
case TLS1_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_2_VERSION:
case DTLS1_VERSION:
ctype = ssl->s3->tmp.ctype;
ctype_num = ssl->s3->tmp.ctype_num;
@@ -1640,10 +2588,6 @@
mode |= SSL_MODE_SMALL_BUFFERS; /* lazily allocate record buffers; usually saves
* 44k over the default */
#endif
-#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) /* not all SSL versions have this */
- mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH; /* enable sending of client data as soon as
- * ClientCCS and ClientFinished are sent */
-#endif
SSL_CTX_set_mode(sslCtx.get(), mode);
SSL_CTX_set_cert_verify_callback(sslCtx.get(), cert_verify_callback, NULL);
@@ -1671,6 +2615,37 @@
SSL_CTX_free(ssl_ctx);
}
+static void NativeCrypto_SSL_CTX_set_session_id_context(JNIEnv* env, jclass,
+ jint ssl_ctx_address, jbyteArray sid_ctx)
+{
+ SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
+ JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context sid_ctx=%p", ssl_ctx, sid_ctx);
+ if (ssl_ctx == NULL) {
+ return;
+ }
+
+ ScopedByteArrayRO buf(env, sid_ctx);
+ if (buf.get() == NULL) {
+ JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => threw exception", ssl_ctx);
+ return;
+ }
+
+ unsigned int length = buf.size();
+ if (length > SSL_MAX_SSL_SESSION_ID_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "length > SSL_MAX_SSL_SESSION_ID_LENGTH");
+ JNI_TRACE("NativeCrypto_SSL_CTX_set_session_id_context => length = %d", length);
+ return;
+ }
+ const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buf.get());
+ int result = SSL_CTX_set_session_id_context(ssl_ctx, bytes, length);
+ if (result == 0) {
+ throwExceptionIfNecessary(env, "NativeCrypto_SSL_CTX_set_session_id_context");
+ return;
+ }
+ JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => ok", ssl_ctx);
+}
+
/**
* public static native int SSL_new(int ssl_ctx) throws SSLException;
*/
@@ -1703,6 +2678,30 @@
return (jint) ssl.release();
}
+static void NativeCrypto_SSL_use_OpenSSL_PrivateKey(JNIEnv* env, jclass, jint ssl_address, jint pkeyRef) {
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("ssl=%p SSL_use_OpenSSL_PrivateKey privatekey=%p", ssl, pkey);
+ if (ssl == NULL) {
+ return;
+ }
+
+ if (pkey == NULL) {
+ return;
+ }
+
+ int ret = SSL_use_PrivateKey(ssl, pkey);
+ if (ret != 1) {
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key");
+ SSL_clear(ssl);
+ JNI_TRACE("ssl=%p SSL_use_OpenSSL_PrivateKey => error", ssl);
+ return;
+ }
+
+ JNI_TRACE("ssl=%p SSL_use_OpenSSL_PrivateKey => ok", ssl);
+}
+
static void NativeCrypto_SSL_use_PrivateKey(JNIEnv* env, jclass,
jint ssl_address, jbyteArray privatekey)
{
@@ -1720,7 +2719,7 @@
const unsigned char* tmp = reinterpret_cast<const unsigned char*>(buf.get());
Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, buf.size()));
if (pkcs8.get() == NULL) {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE,
"Error parsing private key from DER to PKCS8");
SSL_clear(ssl);
@@ -1730,7 +2729,7 @@
Unique_EVP_PKEY privatekeyevp(EVP_PKCS82PKEY(pkcs8.get()));
if (privatekeyevp.get() == NULL) {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE,
"Error creating private key from PKCS8");
SSL_clear(ssl);
@@ -1744,7 +2743,7 @@
if (ret == 1) {
OWNERSHIP_TRANSFERRED(privatekeyevp);
} else {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key");
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_use_PrivateKey => error", ssl);
@@ -1795,7 +2794,7 @@
certificatesX509[i].reset(d2i_X509(NULL, &tmp, buf.size()));
if (certificatesX509[i].get() == NULL) {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate");
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl);
@@ -1807,7 +2806,7 @@
if (ret == 1) {
OWNERSHIP_TRANSFERRED(certificatesX509[0]);
} else {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate");
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate error", ssl);
@@ -1903,7 +2902,7 @@
Unique_X509_NAME principalX509Name(d2i_X509_NAME(NULL, &tmp, buf.size()));
if (principalX509Name.get() == NULL) {
- LOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
+ ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL));
throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing principal");
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals parsing error",
@@ -2171,14 +3170,103 @@
}
/**
- * Perform SSL handshake
+ * Callback for the client to select a protocol.
*/
-static jint NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass,
- jint ssl_address, jobject fdObject, jobject shc, jint timeout, jboolean client_mode)
+static int next_proto_select_callback(SSL* ssl, unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *)
+{
+ JNI_TRACE("ssl=%p next_proto_select_callback", ssl);
+
+ // Enable False Start on the client if the server understands NPN
+ // http://www.imperialviolet.org/2012/04/11/falsestart.html
+ SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH);
+
+ AppData* appData = toAppData(ssl);
+ unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData);
+ size_t npnProtocolsLength = appData->npnProtocolsLength;
+
+ int status = SSL_select_next_proto(out, outlen, in, inlen, npnProtocols, npnProtocolsLength);
+ switch (status) {
+ case OPENSSL_NPN_NEGOTIATED:
+ JNI_TRACE("ssl=%p next_proto_select_callback NPN negotiated", ssl);
+ break;
+ case OPENSSL_NPN_UNSUPPORTED:
+ JNI_TRACE("ssl=%p next_proto_select_callback NPN unsupported", ssl);
+ break;
+ case OPENSSL_NPN_NO_OVERLAP:
+ JNI_TRACE("ssl=%p next_proto_select_callback NPN no overlap", ssl);
+ break;
+ }
+ return SSL_TLSEXT_ERR_OK;
+}
+
+/**
+ * Callback for the server to advertise available protocols.
+ */
+static int next_protos_advertised_callback(SSL* ssl,
+ const unsigned char **out, unsigned int *outlen, void *)
+{
+ JNI_TRACE("ssl=%p next_protos_advertised_callback", ssl);
+ AppData* appData = toAppData(ssl);
+ unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData);
+ if (npnProtocols != NULL) {
+ *out = npnProtocols;
+ *outlen = appData->npnProtocolsLength;
+ }
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static void NativeCrypto_SSL_CTX_enable_npn(JNIEnv* env, jclass, jint ssl_ctx_address)
+{
+ SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
+ if (ssl_ctx == NULL) {
+ return;
+ }
+ SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); // client
+ SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_protos_advertised_callback, NULL); // server
+}
+
+static void NativeCrypto_SSL_CTX_disable_npn(JNIEnv* env, jclass, jint ssl_ctx_address)
+{
+ SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);
+ if (ssl_ctx == NULL) {
+ return;
+ }
+ SSL_CTX_set_next_proto_select_cb(ssl_ctx, NULL, NULL); // client
+ SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, NULL, NULL); // server
+}
+
+static jbyteArray NativeCrypto_SSL_get_npn_negotiated_protocol(JNIEnv* env, jclass,
+ jint ssl_address)
{
SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd=%p shc=%p timeout=%d client_mode=%d",
- ssl, fdObject, shc, timeout, client_mode);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_npn_negotiated_protocol", ssl);
+ if (ssl == NULL) {
+ return NULL;
+ }
+ const jbyte* npn;
+ unsigned npnLength;
+ SSL_get0_next_proto_negotiated(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength);
+ if (npnLength == 0) {
+ return NULL;
+ }
+ jbyteArray result = env->NewByteArray(npnLength);
+ if (result != NULL) {
+ env->SetByteArrayRegion(result, 0, npnLength, npn);
+ }
+ return result;
+}
+
+/**
+ * Perform SSL handshake
+ */
+static jint NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass, jint ssl_address,
+ jobject fdObject, jobject shc, jint timeout_millis, jboolean client_mode,
+ jbyteArray npnProtocols)
+{
+ SSL* ssl = to_SSL(env, ssl_address, true);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd=%p shc=%p timeout_millis=%d client_mode=%d npn=%p",
+ ssl, fdObject, shc, timeout_millis, client_mode, npnProtocols);
if (ssl == NULL) {
return 0;
}
@@ -2233,6 +3321,7 @@
JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake appData => 0", ssl);
return 0;
}
+
SSL_set_app_data(ssl, reinterpret_cast<char*>(appData));
JNI_TRACE("ssl=%p AppData::create => %p", ssl, appData);
@@ -2246,7 +3335,7 @@
while (appData->aliveAndKicking) {
errno = 0;
- if (!appData->setCallbackState(env, shc, fdObject)) {
+ if (!appData->setCallbackState(env, shc, fdObject, npnProtocols)) {
// SocketException thrown by NetFd.isClosed
SSL_clear(ssl);
JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setCallbackState => 0", ssl);
@@ -2270,8 +3359,8 @@
}
// error case
int sslError = SSL_get_error(ssl, ret);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake ret=%d errno=%d sslError=%d timeout=%d",
- ssl, ret, errno, sslError, timeout);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake ret=%d errno=%d sslError=%d timeout_millis=%d",
+ ssl, ret, errno, sslError, timeout_millis);
/*
* If SSL_do_handshake doesn't succeed due to the socket being
@@ -2283,7 +3372,7 @@
*/
if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) {
appData->waitingThreads++;
- int selectResult = sslSelect(env, sslError, fdObject, appData, timeout);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
// SocketException thrown by NetFd.isClosed
@@ -2305,7 +3394,7 @@
return 0;
}
} else {
- // LOGE("Unknown error %d during handshake", error);
+ // ALOGE("Unknown error %d during handshake", error);
break;
}
}
@@ -2462,7 +3551,7 @@
* cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
*/
static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len,
- int* sslReturnCode, int* sslErrorCode, int timeout) {
+ int* sslReturnCode, int* sslErrorCode, int timeout_millis) {
JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len);
if (len == 0) {
@@ -2486,7 +3575,7 @@
unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
- if (!appData->setCallbackState(env, shc, fdObject)) {
+ if (!appData->setCallbackState(env, shc, fdObject, NULL)) {
MUTEX_UNLOCK(appData->mutex);
return THROWN_EXCEPTION;
}
@@ -2541,7 +3630,7 @@
// Need to wait for availability of underlying layer, then retry.
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: {
- int selectResult = sslSelect(env, sslError, fdObject, appData, timeout);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
return THROWN_EXCEPTION;
}
@@ -2592,11 +3681,12 @@
* Returns 1 (success) or value <= 0 (failure).
*/
static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jobject fdObject,
- jobject shc, jbyteArray b, jint offset, jint len, jint timeout)
+ jobject shc, jbyteArray b, jint offset, jint len,
+ jint timeout_millis)
{
SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d timeout=%d",
- ssl, fdObject, shc, b, offset, len, timeout);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d timeout_millis=%d",
+ ssl, fdObject, shc, b, offset, len, timeout_millis);
if (ssl == NULL) {
return 0;
}
@@ -2620,7 +3710,7 @@
int sslErrorCode = SSL_ERROR_NONE;;
int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len,
- &returnCode, &sslErrorCode, timeout);
+ &returnCode, &sslErrorCode, timeout_millis);
int result;
switch (ret) {
@@ -2686,8 +3776,8 @@
unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
- // LOGD("Doing SSL_write() with %d bytes to go", len);
- if (!appData->setCallbackState(env, shc, fdObject)) {
+ // ALOGD("Doing SSL_write() with %d bytes to go", len);
+ if (!appData->setCallbackState(env, shc, fdObject, NULL)) {
MUTEX_UNLOCK(appData->mutex);
return THROWN_EXCEPTION;
}
@@ -2890,7 +3980,7 @@
AppData* appData = toAppData(ssl);
if (appData != NULL) {
- if (!appData->setCallbackState(env, shc, fdObject)) {
+ if (!appData->setCallbackState(env, shc, fdObject, NULL)) {
// SocketException thrown by NetFd.isClosed
SSL_clear(ssl);
freeOpenSslErrorState();
@@ -3138,9 +4228,26 @@
#define SSL_CALLBACKS "Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$SSLHandshakeCallbacks;"
static JNINativeMethod sNativeCryptoMethods[] = {
NATIVE_METHOD(NativeCrypto, clinit, "()V"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_load_dynamic, "()V"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_by_id, "(Ljava/lang/String;)I"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_init, "(I)I"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_finish, "(I)I"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_free, "(I)I"),
+ NATIVE_METHOD(NativeCrypto, ENGINE_load_private_key, "(ILjava/lang/String;)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_DSA, "([B[B[B[B[B)I"),
- NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(I)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(I)[B"),
+ NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)I"),
+ NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(I)[B"),
+ NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)I"),
+ NATIVE_METHOD(NativeCrypto, RSA_generate_key_ex, "(I[B)I"),
+ NATIVE_METHOD(NativeCrypto, get_RSA_private_params, "(I)[[B"),
+ NATIVE_METHOD(NativeCrypto, get_RSA_public_params, "(I)[[B"),
+ NATIVE_METHOD(NativeCrypto, DSA_generate_key, "(I[B[B[B[B)I"),
+ NATIVE_METHOD(NativeCrypto, get_DSA_params, "(I)[[B"),
NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_destroy, "(I)V"),
NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_copy, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_DigestFinal, "(I[BI)I"),
@@ -3149,14 +4256,24 @@
NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_DigestUpdate, "(I[BII)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_SignInit, "(Ljava/lang/String;)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_SignUpdate, "(I[BII)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_SignFinal, "(I[BII)I"),
NATIVE_METHOD(NativeCrypto, EVP_VerifyInit, "(Ljava/lang/String;)I"),
NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdate, "(I[BII)V"),
NATIVE_METHOD(NativeCrypto, EVP_VerifyFinal, "(I[BIII)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_get_cipherbyname, "(Ljava/lang/String;)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_CipherInit_ex, "(I[B[BZ)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_CipherUpdate, "(I[BI[BI)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_CipherFinal_ex, "(I[BI)I"),
+ NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_cleanup, "(I)V"),
NATIVE_METHOD(NativeCrypto, RAND_seed, "([B)V"),
NATIVE_METHOD(NativeCrypto, RAND_load_file, "(Ljava/lang/String;J)I"),
NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()I"),
NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(I[B)V"),
NATIVE_METHOD(NativeCrypto, SSL_new, "(I)I"),
+ NATIVE_METHOD(NativeCrypto, SSL_use_OpenSSL_PrivateKey, "(II)V"),
NATIVE_METHOD(NativeCrypto, SSL_use_PrivateKey, "(I[B)V"),
NATIVE_METHOD(NativeCrypto, SSL_use_certificate, "(I[[B)V"),
NATIVE_METHOD(NativeCrypto, SSL_check_private_key, "(I)V"),
@@ -3173,7 +4290,7 @@
NATIVE_METHOD(NativeCrypto, SSL_set_session_creation_enabled, "(IZ)V"),
NATIVE_METHOD(NativeCrypto, SSL_set_tlsext_host_name, "(ILjava/lang/String;)V"),
NATIVE_METHOD(NativeCrypto, SSL_get_servername, "(I)Ljava/lang/String;"),
- NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(I" FILE_DESCRIPTOR SSL_CALLBACKS "IZ)I"),
+ NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(I" FILE_DESCRIPTOR SSL_CALLBACKS "IZ[B)I"),
NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(I)V"),
NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(I)[[B"),
NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(I)[[B"),
@@ -3190,13 +4307,13 @@
NATIVE_METHOD(NativeCrypto, SSL_SESSION_free, "(I)V"),
NATIVE_METHOD(NativeCrypto, i2d_SSL_SESSION, "(I)[B"),
NATIVE_METHOD(NativeCrypto, d2i_SSL_SESSION, "([B)I"),
+ NATIVE_METHOD(NativeCrypto, SSL_CTX_enable_npn, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, SSL_CTX_disable_npn, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, SSL_get_npn_negotiated_protocol, "(I)[B"),
};
-int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) {
+void register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) {
JNI_TRACE("register_org_apache_harmony_xnet_provider_jsse_NativeCrypto");
// Register org.apache.harmony.xnet.provider.jsse.NativeCrypto methods
- return jniRegisterNativeMethods(env,
- "org/apache/harmony/xnet/provider/jsse/NativeCrypto",
- sNativeCryptoMethods,
- NELEM(sNativeCryptoMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/xnet/provider/jsse/NativeCrypto", sNativeCryptoMethods, NELEM(sNativeCryptoMethods));
}
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index 9535ce6..b67348b 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -58,19 +58,9 @@
external/openssl/include \
external/zlib
-# Any shared/static libs that are listed here must also
-# be listed in libs/nativehelper/Android.mk.
-# TODO: fix this requirement
-
LOCAL_SHARED_LIBRARIES += \
- libcrypto \
- libcutils \
- libexpat \
- libicuuc \
- libicui18n \
- libssl \
- libutils \
- libz
+ liblog \
+ libnativehelper
LOCAL_STATIC_LIBRARIES += \
libfdlibm
diff --git a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
new file mode 100644
index 0000000..85e360e
--- /dev/null
+++ b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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.android.org.bouncycastle.jce.provider;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.HashSet;
+import java.util.Set;
+import junit.framework.TestCase;
+import com.android.org.bouncycastle.jce.provider.CertBlacklist;
+import com.android.org.bouncycastle.util.encoders.Hex;
+
+public class CertBlacklistTest extends TestCase {
+
+ private File tmpFile;
+
+ private Set<String> DEFAULT_PUBKEYS;
+ private Set<String> DEFAULT_SERIALS;
+
+ public CertBlacklistTest() throws IOException {
+ tmpFile = File.createTempFile("test", "");
+ DEFAULT_PUBKEYS = getDefaultPubkeys();
+ DEFAULT_SERIALS = getDefaultSerials();
+ tmpFile.delete();
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tmpFile = File.createTempFile("test", "");
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ tmpFile.delete();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private Set<String> getPubkeyBlacklist(String path) throws IOException {
+ // set our blacklist path
+ CertBlacklist bl = new CertBlacklist(path, CertBlacklist.DEFAULT_SERIAL_BLACKLIST_PATH);
+ // call readPubkeyBlacklist
+ Set<byte[]> arr = bl.pubkeyBlacklist;
+ // convert the results to a hashset of strings
+ Set<String> results = new HashSet<String>();
+ for (byte[] value: arr) {
+ results.add(new String(Hex.encode(value)));
+ }
+ return results;
+ }
+
+ private Set<String> getSerialBlacklist(String path) throws IOException {
+ // set our blacklist path
+ CertBlacklist bl = new CertBlacklist(CertBlacklist.DEFAULT_PUBKEY_BLACKLIST_PATH, path);
+ // call readPubkeyBlacklist
+ Set<BigInteger> arr = bl.serialBlacklist;
+ // convert the results to a hashset of strings
+ Set<String> results = new HashSet<String>();
+ for (BigInteger value: arr) {
+ results.add(value.toString(16));
+ }
+ return results;
+ }
+
+ private Set<String> getDefaultPubkeys() throws IOException {
+ return getPubkeyBlacklist("");
+ }
+
+ private Set<String> getDefaultSerials() throws IOException {
+ return getSerialBlacklist("");
+ }
+
+ private Set<String> getCurrentPubkeyBlacklist() throws IOException {
+ return getPubkeyBlacklist(tmpFile.getCanonicalPath());
+ }
+
+ private Set<String> getCurrentSerialBlacklist() throws IOException {
+ return getSerialBlacklist(tmpFile.getCanonicalPath());
+ }
+
+ private void blacklistToFile(String blacklist) throws IOException {
+ FileOutputStream out = new FileOutputStream(tmpFile);
+ out.write(blacklist.toString().getBytes());
+ out.close();
+ }
+
+ private void writeBlacklist(HashSet<String> values) throws IOException {
+ StringBuilder result = new StringBuilder();
+ // join the values into a string
+ for (String value : values) {
+ if (result.length() != 0) {
+ result.append(",");
+ }
+ result.append(value);
+ }
+ blacklistToFile(result.toString());
+ }
+
+ public void testPubkeyBlacklistLegit() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default pubkeys into the bl
+ bl.addAll(DEFAULT_PUBKEYS);
+ // do the test
+ assertEquals(bl, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistLegit() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default serials into the bl
+ bl.addAll(DEFAULT_SERIALS);
+ // do the test
+ assertEquals(bl, getCurrentSerialBlacklist());
+ }
+
+ public void testPubkeyBlacklistMultipleLegit() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccd");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default pubkeys into the bl
+ bl.addAll(DEFAULT_PUBKEYS);
+ // do the test
+ assertEquals(bl, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistMultipleLegit() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
+ bl.add("22e514121e61c643b1e9b06bd4b9f7d1");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default serials into the bl
+ bl.addAll(DEFAULT_SERIALS);
+ // do the test
+ assertEquals(bl, getCurrentSerialBlacklist());
+ }
+
+ public void testPubkeyBlacklistMultipleBad() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
+ bl.add("");
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccd");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default pubkeys into the bl
+ bl.addAll(DEFAULT_PUBKEYS);
+ // remove the bad one
+ bl.remove("");
+ // do the test- results should be all but the bad one are handled
+ assertEquals(bl, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistMultipleBad() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
+ bl.add("");
+ bl.add("22e514121e61c643b1e9b06bd4b9f7d1");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default serials into the bl
+ bl.addAll(DEFAULT_SERIALS);
+ // remove the bad one
+ bl.remove("");
+ // do the test- results should be all but the bad one are handled
+ assertEquals(bl, getCurrentSerialBlacklist());
+ }
+
+ public void testPubkeyBlacklistDoesntExist() throws IOException {
+ assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistDoesntExist() throws IOException {
+ assertEquals(DEFAULT_SERIALS, getCurrentSerialBlacklist());
+ }
+
+ public void testPubkeyBlacklistNotHexValues() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
+ // write the blacklist
+ writeBlacklist(bl);
+ // do the test
+ assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistNotHexValues() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
+ // write the blacklist
+ writeBlacklist(bl);
+ // do the test
+ assertEquals(DEFAULT_SERIALS, getCurrentSerialBlacklist());
+ }
+
+ public void testPubkeyBlacklistIncorrectLength() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091cc");
+ // write the blacklist
+ writeBlacklist(bl);
+ // do the test
+ assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
+ }
+
+ public void testSerialBlacklistZero() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("0");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default serials
+ bl.addAll(DEFAULT_SERIALS);
+ // do the test
+ assertEquals(bl, getCurrentSerialBlacklist());
+ }
+
+ public void testSerialBlacklistNegative() throws IOException {
+ // build the blacklist
+ HashSet<String> bl = new HashSet<String>();
+ bl.add("-1");
+ // write the blacklist
+ writeBlacklist(bl);
+ // add the default serials
+ bl.addAll(DEFAULT_SERIALS);
+ // do the test
+ assertEquals(bl, getCurrentSerialBlacklist());
+ }
+}
diff --git a/luni/src/test/java/libcore/io/DiskLruCacheTest.java b/luni/src/test/java/libcore/io/DiskLruCacheTest.java
index 808918d..03a6932 100644
--- a/luni/src/test/java/libcore/io/DiskLruCacheTest.java
+++ b/luni/src/test/java/libcore/io/DiskLruCacheTest.java
@@ -602,6 +602,59 @@
assertAbsent("A");
}
+ public void testEditSameVersion() throws Exception {
+ set("A", "a", "a");
+ DiskLruCache.Snapshot snapshot = cache.get("A");
+ DiskLruCache.Editor editor = snapshot.edit();
+ editor.set(1, "a2");
+ editor.commit();
+ assertValue("A", "a", "a2");
+ }
+
+ public void testEditSnapshotAfterChangeAborted() throws Exception {
+ set("A", "a", "a");
+ DiskLruCache.Snapshot snapshot = cache.get("A");
+ DiskLruCache.Editor toAbort = snapshot.edit();
+ toAbort.set(0, "b");
+ toAbort.abort();
+ DiskLruCache.Editor editor = snapshot.edit();
+ editor.set(1, "a2");
+ editor.commit();
+ assertValue("A", "a", "a2");
+ }
+
+ public void testEditSnapshotAfterChangeCommitted() throws Exception {
+ set("A", "a", "a");
+ DiskLruCache.Snapshot snapshot = cache.get("A");
+ DiskLruCache.Editor toAbort = snapshot.edit();
+ toAbort.set(0, "b");
+ toAbort.commit();
+ assertNull(snapshot.edit());
+ }
+
+ public void testEditSinceEvicted() throws Exception {
+ cache.close();
+ cache = DiskLruCache.open(cacheDir, appVersion, 2, 10);
+ set("A", "aa", "aaa"); // size 5
+ DiskLruCache.Snapshot snapshot = cache.get("A");
+ set("B", "bb", "bbb"); // size 5
+ set("C", "cc", "ccc"); // size 5; will evict 'A'
+ cache.flush();
+ assertNull(snapshot.edit());
+ }
+
+ public void testEditSinceEvictedAndRecreated() throws Exception {
+ cache.close();
+ cache = DiskLruCache.open(cacheDir, appVersion, 2, 10);
+ set("A", "aa", "aaa"); // size 5
+ DiskLruCache.Snapshot snapshot = cache.get("A");
+ set("B", "bb", "bbb"); // size 5
+ set("C", "cc", "ccc"); // size 5; will evict 'A'
+ set("A", "a", "aaaa"); // size 5; will evict 'B'
+ cache.flush();
+ assertNull(snapshot.edit());
+ }
+
private void assertJournalEquals(String... expectedBodyLines) throws Exception {
List<String> expectedLines = new ArrayList<String>();
expectedLines.add(MAGIC);
diff --git a/luni/src/test/java/libcore/java/io/CharArrayWriterTest.java b/luni/src/test/java/libcore/java/io/CharArrayWriterTest.java
new file mode 100644
index 0000000..7e4dd42
--- /dev/null
+++ b/luni/src/test/java/libcore/java/io/CharArrayWriterTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 libcore.java.io;
+
+import java.io.CharArrayWriter;
+import junit.framework.TestCase;
+
+public final class CharArrayWriterTest extends TestCase {
+ public void testCharArrayWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ CharArrayWriter a = new CharArrayWriter();
+ CharArrayWriter b = new CharArrayWriter();
+
+ a.write(str, 0, 26);
+ a.write('X');
+ a.writeTo(b);
+
+ assertEquals(27, a.size());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+
+ b.write("alphabravodelta", 5, 5);
+ b.append('X');
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", b.toString());
+ b.append("omega");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", b.toString());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
index d59111d..3cf621e 100644
--- a/luni/src/test/java/libcore/java/io/FileTest.java
+++ b/luni/src/test/java/libcore/java/io/FileTest.java
@@ -146,13 +146,6 @@
// http://b/3047893 - getCanonicalPath wasn't actually resolving symbolic links.
public void test_getCanonicalPath() throws Exception {
- if (new File("/sdcard").exists()) {
- // This assumes the current Android setup where /sdcard is a symbolic link to
- // /mnt/sdcard.
- File testFile = new File("/sdcard/test1.txt");
- assertEquals("/mnt/sdcard/test1.txt", testFile.getCanonicalPath());
- }
-
// This assumes you can create symbolic links in the temporary directory. This isn't
// true on Android if you're using /sdcard. It will work in /data/local though.
File base = createTemporaryDirectory();
diff --git a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
index 11142d5..afe49b7 100644
--- a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.RandomAccessFile;
import junit.framework.TestCase;
+import libcore.java.lang.ref.FinalizationTester;
public final class RandomAccessFileTest extends TestCase {
@@ -69,8 +70,7 @@
File file = File.createTempFile("RandomAccessFileTest", "tmp");
for (int i = 0; i < tooManyOpenFiles; i++) {
createRandomAccessFile(file);
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
}
}
private void createRandomAccessFile(File file) throws Exception {
diff --git a/luni/src/test/java/libcore/java/io/SerializationTest.java b/luni/src/test/java/libcore/java/io/SerializationTest.java
index 74becfe..434dd56 100644
--- a/luni/src/test/java/libcore/java/io/SerializationTest.java
+++ b/luni/src/test/java/libcore/java/io/SerializationTest.java
@@ -16,9 +16,11 @@
package libcore.java.io;
+import java.io.IOException;
+import java.io.InvalidClassException;
import java.io.Serializable;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public final class SerializationTest extends TestCase {
@@ -28,7 +30,7 @@
String s = "aced0005737200346c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
+ "374244669656c644d6164655472616e7369656e74000000000000000002000149000c7472616e736"
+ "9656e74496e747870abababab";
- FieldMadeTransient deserialized = (FieldMadeTransient) SerializableTester.deserializeHex(s);
+ FieldMadeTransient deserialized = (FieldMadeTransient) SerializationTester.deserializeHex(s);
assertEquals(0, deserialized.transientInt);
}
@@ -36,4 +38,36 @@
private static final long serialVersionUID = 0L;
private transient int transientInt;
}
+
+ public void testSerialVersionUidChange() throws Exception {
+ // this was created by serializing a SerialVersionUidChanged with serialVersionUID = 0L
+ String s = "aced0005737200396c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
+ + "3742453657269616c56657273696f6e5569644368616e67656400000000000000000200014900016"
+ + "1787000000003";
+ try {
+ SerializationTester.deserializeHex(s);
+ fail();
+ } catch (InvalidClassException expected) {
+ }
+ }
+
+ static class SerialVersionUidChanged implements Serializable {
+ private static final long serialVersionUID = 1L; // was 0L
+ private int a;
+ }
+
+ public void testMissingSerialVersionUid() throws Exception {
+ // this was created by serializing a FieldsChanged with one int field named 'a'
+ String s = "aced00057372002f6c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e54657"
+ + "374244669656c64734368616e6765643bcfb934e310fa1c02000149000161787000000003";
+ try {
+ SerializationTester.deserializeHex(s);
+ fail();
+ } catch (InvalidClassException expected) {
+ }
+ }
+
+ static class FieldsChanged implements Serializable {
+ private int b; // was 'a'
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/AssertionErrorTest.java b/luni/src/test/java/libcore/java/lang/AssertionErrorTest.java
new file mode 100644
index 0000000..638b15b
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/AssertionErrorTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 libcore.java.lang;
+
+import junit.framework.TestCase;
+
+public final class AssertionErrorTest extends TestCase {
+ // http://code.google.com/p/android/issues/detail?id=29378
+ public void test_29378() throws Exception {
+ AssertionError ae = new AssertionError("hello");
+ ae.initCause(new Throwable());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/EnumTest.java b/luni/src/test/java/libcore/java/lang/EnumTest.java
new file mode 100644
index 0000000..bae42c0
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/EnumTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 libcore.java.lang;
+
+import junit.framework.TestCase;
+import libcore.util.SerializationTester;
+
+public final class EnumTest extends TestCase {
+ public void testEnumSerialization() {
+ String s = "aced00057e7200236c6962636f72652e6a6176612e6c616e672e456e756d5465"
+ + "737424526f7368616d626f00000000000000001200007872000e6a6176612e6c6"
+ + "16e672e456e756d000000000000000012000078707400055041504552";
+ Roshambo value = Roshambo.PAPER;
+ assertTrue(value.getClass() == Roshambo.class);
+ new SerializationTester<Roshambo>(value, s).test();
+ }
+
+ public void testEnumSubclassSerialization() {
+ String s = "aced00057e7200236c6962636f72652e6a6176612e6c616e672e456e756d5465"
+ + "737424526f7368616d626f00000000000000001200007872000e6a6176612e6c6"
+ + "16e672e456e756d00000000000000001200007870740004524f434b";
+ Roshambo value = Roshambo.ROCK;
+ assertTrue(value.getClass() != Roshambo.class);
+ new SerializationTester<Roshambo>(value, s).test();
+ }
+
+ enum Roshambo {
+ ROCK {
+ @Override public String toString() {
+ return "rock!";
+ }
+ },
+ PAPER,
+ SCISSORS
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/LongTest.java b/luni/src/test/java/libcore/java/lang/LongTest.java
index 08bdd15..9e143da 100644
--- a/luni/src/test/java/libcore/java/lang/LongTest.java
+++ b/luni/src/test/java/libcore/java/lang/LongTest.java
@@ -31,4 +31,12 @@
assertTrue(Long.compare(min, zero) < 0);
assertTrue(Long.compare(min, max) < 0);
}
+
+ public void test_signum() throws Exception {
+ assertEquals(0, Long.signum(0));
+ assertEquals(1, Long.signum(1));
+ assertEquals(-1, Long.signum(-1));
+ assertEquals(1, Long.signum(Long.MAX_VALUE));
+ assertEquals(-1, Long.signum(Long.MIN_VALUE));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/OldRuntimeTest.java b/luni/src/test/java/libcore/java/lang/OldRuntimeTest.java
index 4b692d7..0926569 100644
--- a/luni/src/test/java/libcore/java/lang/OldRuntimeTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldRuntimeTest.java
@@ -17,7 +17,6 @@
package libcore.java.lang;
-import dalvik.annotation.KnownFailure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -462,7 +461,6 @@
Runtime.getRuntime().traceInstructions(false);
}
- @KnownFailure("Fails in CTS but passes under run-core-tests")
public void test_traceMethodCalls() {
try {
Runtime.getRuntime().traceMethodCalls(false);
diff --git a/luni/src/test/java/libcore/java/lang/OldThreadTest.java b/luni/src/test/java/libcore/java/lang/OldThreadTest.java
index 1e189f6..2b304f2 100644
--- a/luni/src/test/java/libcore/java/lang/OldThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldThreadTest.java
@@ -21,6 +21,7 @@
import java.io.PrintStream;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.LockSupport;
+import libcore.java.lang.ref.FinalizationTester;
public class OldThreadTest extends junit.framework.TestCase {
@@ -478,7 +479,7 @@
spinner = null;
st = null;
ct = null;
- System.runFinalization();
+ FinalizationTester.induceFinalization();
} catch (Exception e) {
}
}
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index 3695e3e..998afdb 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -17,10 +17,21 @@
package libcore.java.lang;
import java.util.concurrent.atomic.AtomicInteger;
+import junit.framework.Assert;
import junit.framework.TestCase;
+import libcore.java.lang.ref.FinalizationTester;
public final class ThreadTest extends TestCase {
+ /**
+ * getContextClassLoader returned a non-application class loader.
+ * http://code.google.com/p/android/issues/detail?id=5697
+ */
+ public void testJavaContextClassLoader() throws Exception {
+ Assert.assertNotNull("Must have a Java context ClassLoader",
+ Thread.currentThread().getContextClassLoader());
+ }
+
public void testLeakingStartedThreads() {
final AtomicInteger finalizedThreadsCount = new AtomicInteger();
for (int i = 0; true; i++) {
@@ -30,7 +41,7 @@
break;
}
}
- System.runFinalization();
+ FinalizationTester.induceFinalization();
assertTrue("Started threads were never finalized!", finalizedThreadsCount.get() > 0);
}
@@ -43,7 +54,7 @@
break;
}
}
- System.runFinalization();
+ FinalizationTester.induceFinalization();
assertTrue("Unstarted threads were never finalized!", finalizedThreadsCount.get() > 0);
}
@@ -56,4 +67,46 @@
}
};
}
+
+ /**
+ * Thread.getStackTrace() is broken. http://b/1252043
+ */
+ public void testGetStackTrace() throws Exception {
+ Thread t1 = new Thread("t1") {
+ @Override public void run() {
+ doSomething();
+ }
+ public void doSomething() {
+ for (int i = 0; i < 20;) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ };
+ t1.start();
+ Thread.sleep(1000);
+ StackTraceElement[] traces = t1.getStackTrace();
+ StackTraceElement trace = traces[traces.length - 2];
+
+ // Expect to find MyThread.doSomething in the trace
+ assertTrue(trace.getClassName().contains("ThreadTest")
+ && trace.getMethodName().equals("doSomething"));
+ }
+
+ public void testGetAllStackTracesIncludesAllGroups() throws Exception {
+ final AtomicInteger visibleTraces = new AtomicInteger();
+ ThreadGroup group = new ThreadGroup("1");
+ Thread t2 = new Thread(group, "t2") {
+ @Override public void run() {
+ visibleTraces.set(Thread.getAllStackTraces().size());
+ }
+ };
+ t2.start();
+ t2.join();
+
+ // Expect to see the traces of all threads (not just t2)
+ assertTrue("Must have traces for all threads", visibleTraces.get() > 1);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/ThrowableTest.java b/luni/src/test/java/libcore/java/lang/ThrowableTest.java
index 700f616..1906784c 100644
--- a/luni/src/test/java/libcore/java/lang/ThrowableTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThrowableTest.java
@@ -20,7 +20,7 @@
import java.io.StringWriter;
import java.util.Arrays;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public class ThrowableTest extends TestCase {
private static class NoStackTraceException extends Exception {
@@ -248,7 +248,7 @@
+ "00000007078";
Throwable throwable = new SuppressionsThrowable("foo", null, false);
throwable.setStackTrace(new StackTraceElement[0]);
- new SerializableTester<Throwable>(throwable, s) {
+ new SerializationTester<Throwable>(throwable, s) {
@Override protected boolean equals(Throwable a, Throwable b) {
return printStackTraceToString(a).equals(printStackTraceToString(b));
}
@@ -277,7 +277,7 @@
+ "870000000007704000000007871007e000f78";
Throwable throwable = new SuppressionsThrowable("foo", null, true);
throwable.setStackTrace(new StackTraceElement[0]);
- new SerializableTester<Throwable>(throwable, s) {
+ new SerializationTester<Throwable>(throwable, s) {
@Override protected boolean equals(Throwable a, Throwable b) {
return printStackTraceToString(a).equals(printStackTraceToString(b));
}
@@ -291,7 +291,7 @@
}
private void assertSerialized(final Throwable throwable, String golden) {
- new SerializableTester<Throwable>(throwable, golden) {
+ new SerializationTester<Throwable>(throwable, golden) {
@Override protected boolean equals(Throwable a, Throwable b) {
return printStackTraceToString(a).equals(printStackTraceToString(b));
}
diff --git a/luni/src/test/java/libcore/java/lang/ref/FinalizationTester.java b/luni/src/test/java/libcore/java/lang/ref/FinalizationTester.java
new file mode 100644
index 0000000..66ac1a4
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/ref/FinalizationTester.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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 libcore.java.lang.ref;
+
+/**
+ * Triggers finalizers to run. Note that live-precise bugs may interfere with
+ * analysis of what is reachable. Unreachable references in local frames may not
+ * be finalized even after a call to {@link #induceFinalization}. To work
+ * around, create finalizable objects in helper methods. http://b/4191345
+ */
+public final class FinalizationTester {
+ private FinalizationTester() {}
+
+ public static void induceFinalization() {
+ System.gc();
+ enqueueReferences();
+ System.runFinalization();
+ }
+
+ public static void enqueueReferences() {
+ /*
+ * Hack. We don't have a programmatic way to wait for the reference queue
+ * daemon to move references to the appropriate queues.
+ */
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
index b6f930c..10a26fe 100644
--- a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
+++ b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
@@ -27,17 +27,13 @@
AtomicBoolean finalized = new AtomicBoolean();
createFinalizableObject(finalized);
- induceFinalization();
+ FinalizationTester.induceFinalization();
if (!finalized.get()) {
fail();
}
}
- /**
- * Prevent live-precise bugs from interfering with analysis of what is
- * reachable. Do not inline this method; otherwise tests may fail on VMs
- * that are not live-precise. http://b/4191345
- */
+ /** Do not inline this method; that could break non-precise GCs. See FinalizationTester. */
private void createFinalizableObject(final AtomicBoolean finalized) {
new X() {
@Override protected void finalize() throws Throwable {
@@ -56,24 +52,10 @@
} catch (AssertionError expected) {
}
- induceFinalization();
+ FinalizationTester.induceFinalization();
assertTrue("object whose constructor threw was not finalized", ConstructionFails.finalized);
}
- private void induceFinalization() throws Exception {
- System.gc();
- enqueueReferences();
- System.runFinalization();
- }
-
- /**
- * Hack. We don't have a programmatic way to wait for the reference queue
- * daemon to move references to the appropriate queues.
- */
- private void enqueueReferences() throws InterruptedException {
- Thread.sleep(100);
- }
-
static class ConstructionFails {
private static boolean finalized;
@@ -97,7 +79,7 @@
createSlowFinalizer(2000, latch);
createSlowFinalizer(4000, latch);
createSlowFinalizer(8000, latch);
- induceFinalization();
+ FinalizationTester.induceFinalization();
latch.await();
}
@@ -119,7 +101,7 @@
AtomicInteger count = new AtomicInteger();
AtomicBoolean keepGoing = new AtomicBoolean(true);
createChainedFinalizer(count, keepGoing);
- induceFinalization();
+ FinalizationTester.induceFinalization();
keepGoing.set(false);
assertTrue(count.get() > 0);
}
@@ -133,7 +115,7 @@
createChainedFinalizer(counter, keepGoing); // recursive!
}
System.gc();
- enqueueReferences();
+ FinalizationTester.enqueueReferences();
}
};
}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ArrayTest.java b/luni/src/test/java/libcore/java/lang/reflect/ArrayTest.java
new file mode 100644
index 0000000..71fa66d
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/ArrayTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 libcore.java.lang.reflect;
+
+import java.lang.reflect.Array;
+import junit.framework.TestCase;
+
+public class ArrayTest extends TestCase {
+ private static boolean[] booleans;
+ private static byte[] bytes;
+ private static char[] chars;
+ private static double[] doubles;
+ private static float[] floats;
+ private static int[] ints;
+ private static long[] longs;
+ private static short[] shorts;
+
+ @Override protected void setUp() throws Exception {
+ super.setUp();
+ booleans = new boolean[] { true };
+ bytes = new byte[] { (byte) 0xff };
+ chars = new char[] { '\uffff' };
+ doubles = new double[] { (double) 0xffffffffffffffffL };
+ floats = new float[] { (float) 0xffffffff };
+ ints = new int[] { 0xffffffff };
+ longs = new long[] { 0xffffffffffffffffL };
+ shorts = new short[] { (short) 0xffff };
+ }
+
+ public void testGetBoolean() throws Exception {
+ assertEquals(booleans[0], Array.getBoolean(booleans, 0));
+ try { Array.getBoolean(bytes, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(chars, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(ints, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(longs, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(shorts, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getBoolean(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetByte() throws Exception {
+ try { Array.getByte(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals(bytes[0], Array.getByte(bytes, 0));
+ try { Array.getByte(chars, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(ints, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(longs, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(shorts, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getByte(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetChar() throws Exception {
+ try { Array.getChar(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(bytes, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals(chars[0], Array.getChar(chars, 0));
+ try { Array.getChar(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(ints, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(longs, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(shorts, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getChar(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetDouble() throws Exception {
+ try { Array.getDouble(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((double) bytes[0], Array.getDouble(bytes, 0));
+ assertEquals((double) chars[0], Array.getDouble(chars, 0));
+ assertEquals(doubles[0], Array.getDouble(doubles, 0));
+ assertEquals((double) floats[0], Array.getDouble(floats, 0));
+ assertEquals((double) ints[0], Array.getDouble(ints, 0));
+ assertEquals((double) longs[0], Array.getDouble(longs, 0));
+ assertEquals((double) shorts[0], Array.getDouble(shorts, 0));
+ try { Array.getDouble(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetFloat() throws Exception {
+ try { Array.getFloat(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((float) bytes[0], Array.getFloat(bytes, 0));
+ assertEquals((float) chars[0], Array.getFloat(chars, 0));
+ assertEquals(floats[0], Array.getFloat(floats, 0));
+ try { Array.getFloat(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((float) ints[0], Array.getFloat(ints, 0));
+ assertEquals((float) longs[0], Array.getFloat(longs, 0));
+ assertEquals((float) shorts[0], Array.getFloat(shorts, 0));
+ try { Array.getFloat(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetInt() throws Exception {
+ try { Array.getInt(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((int) bytes[0], Array.getInt(bytes, 0));
+ assertEquals((int) chars[0], Array.getInt(chars, 0));
+ try { Array.getInt(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getInt(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals(ints[0], Array.getInt(ints, 0));
+ try { Array.getInt(longs, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((int) shorts[0], Array.getInt(shorts, 0));
+ try { Array.getInt(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetLong() throws Exception {
+ try { Array.getLong(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((long) bytes[0], Array.getLong(bytes, 0));
+ assertEquals((long) chars[0], Array.getLong(chars, 0));
+ try { Array.getLong(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getLong(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((long) ints[0], Array.getLong(ints, 0));
+ assertEquals(longs[0], Array.getLong(longs, 0));
+ assertEquals((long) shorts[0], Array.getLong(shorts, 0));
+ try { Array.getLong(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testGetShort() throws Exception {
+ try { Array.getShort(booleans, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals((int) bytes[0], Array.getShort(bytes, 0));
+ try { Array.getShort(chars, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getShort(doubles, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getShort(floats, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getShort(ints, 0); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.getShort(longs, 0); fail(); } catch (IllegalArgumentException expected) {}
+ assertEquals(shorts[0], Array.getShort(shorts, 0));
+ try { Array.getShort(null, 0); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetBoolean() throws Exception {
+ Array.setBoolean(booleans, 0, booleans[0]);
+ try { Array.setBoolean(bytes, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(chars, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(doubles, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(floats, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(ints, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(longs, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(shorts, 0, true); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setBoolean(null, 0, true); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetByte() throws Exception {
+ try { Array.setByte(booleans, 0, bytes[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setByte(bytes, 0, bytes[0]);
+ try { Array.setByte(chars, 0, bytes[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setByte(doubles, 0, bytes[0]);
+ Array.setByte(floats, 0, bytes[0]);
+ Array.setByte(ints, 0, bytes[0]);
+ Array.setByte(longs, 0, bytes[0]);
+ Array.setByte(shorts, 0, bytes[0]);
+ try { Array.setByte(null, 0, bytes[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetChar() throws Exception {
+ try { Array.setChar(booleans, 0, chars[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setChar(bytes, 0, chars[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setChar(chars, 0, chars[0]);
+ Array.setChar(doubles, 0, chars[0]);
+ Array.setChar(floats, 0, chars[0]);
+ Array.setChar(ints, 0, chars[0]);
+ Array.setChar(longs, 0, chars[0]);
+ try { Array.setChar(shorts, 0, chars[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setChar(null, 0, chars[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetDouble() throws Exception {
+ try { Array.setDouble(booleans, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(bytes, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(chars, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setDouble(doubles, 0, doubles[0]);
+ try { Array.setDouble(floats, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(ints, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(longs, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(shorts, 0, doubles[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setDouble(null, 0, doubles[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetFloat() throws Exception {
+ try { Array.setFloat(booleans, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setFloat(bytes, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setFloat(chars, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setFloat(floats, 0, floats[0]);
+ Array.setFloat(doubles, 0, floats[0]);
+ try { Array.setFloat(ints, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setFloat(longs, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setFloat(shorts, 0, floats[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setFloat(null, 0, floats[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetInt() throws Exception {
+ try { Array.setInt(booleans, 0, ints[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setInt(bytes, 0, ints[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setInt(chars, 0, ints[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setInt(doubles, 0, ints[0]);
+ Array.setInt(floats, 0, ints[0]);
+ Array.setInt(ints, 0, ints[0]);
+ Array.setInt(longs, 0, ints[0]);
+ try { Array.setInt(shorts, 0, ints[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setInt(null, 0, ints[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetLong() throws Exception {
+ try { Array.setLong(booleans, 0, longs[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setLong(bytes, 0, longs[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setLong(chars, 0, longs[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setLong(doubles, 0, longs[0]);
+ Array.setLong(floats, 0, longs[0]);
+ try { Array.setLong(ints, 0, longs[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setLong(longs, 0, longs[0]);
+ try { Array.setLong(shorts, 0, longs[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setLong(null, 0, longs[0]); fail(); } catch (NullPointerException expected) {}
+ }
+
+ public void testSetShort() throws Exception {
+ try { Array.setShort(booleans, 0, shorts[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setShort(bytes, 0, shorts[0]); fail(); } catch (IllegalArgumentException expected) {}
+ try { Array.setShort(chars, 0, shorts[0]); fail(); } catch (IllegalArgumentException expected) {}
+ Array.setShort(doubles, 0, shorts[0]);
+ Array.setShort(floats, 0, shorts[0]);
+ Array.setShort(ints, 0, shorts[0]);
+ Array.setShort(longs, 0, shorts[0]);
+ Array.setShort(shorts, 0, shorts[0]);
+ try { Array.setShort(null, 0, shorts[0]); fail(); } catch (NullPointerException expected) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
new file mode 100644
index 0000000..eb3d034
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 libcore.java.lang.reflect;
+
+import java.lang.reflect.Field;
+import junit.framework.TestCase;
+
+public final class FieldTest extends TestCase {
+ private static final long MY_LONG = 5073258162644648461L;
+
+ // Reflection for static long fields was broken http://b/1120750
+ public void testLongFieldReflection() throws Exception {
+ Field field = getClass().getDeclaredField("MY_LONG");
+ assertEquals(5073258162644648461L, field.getLong(null));
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index a059d96..ef30eb8 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -197,6 +197,24 @@
assertEquals(anonymous.getClass(), method.getDeclaringClass());
}
+ // http://b/1045939
+ public void testMethodToString() throws Exception {
+ assertEquals("public final native void java.lang.Object.notify()",
+ Object.class.getMethod("notify", new Class[] { }).toString());
+ assertEquals("public java.lang.String java.lang.Object.toString()",
+ Object.class.getMethod("toString", new Class[] { }).toString());
+ assertEquals("public final native void java.lang.Object.wait(long,int)"
+ + " throws java.lang.InterruptedException",
+ Object.class.getMethod("wait", new Class[] { long.class, int.class }).toString());
+ assertEquals("public boolean java.lang.Object.equals(java.lang.Object)",
+ Object.class.getMethod("equals", new Class[] { Object.class }).toString());
+ assertEquals("public static java.lang.String java.lang.String.valueOf(char[])",
+ String.class.getMethod("valueOf", new Class[] { char[].class }).toString());
+ assertEquals( "public java.lang.Process java.lang.Runtime.exec(java.lang.String[])"
+ + " throws java.io.IOException",
+ Runtime.class.getMethod("exec", new Class[] { String[].class }).toString());
+ }
+
public static class MethodTestHelper {
public void m1() throws IndexOutOfBoundsException { }
public void m2(Object o) { }
diff --git a/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java b/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java
new file mode 100644
index 0000000..0a95bbf
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/OldAndroidClassTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 libcore.java.lang.reflect;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import junit.framework.TestCase;
+
+public final class OldAndroidClassTest extends TestCase {
+ private static final String packageName = "libcore.java.lang.reflect";
+
+ public void testNewInstance() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Object instance = helloClass.newInstance();
+ assertNotNull(instance);
+ }
+
+ public void testForName() throws Exception {
+ try {
+ Class.forName("this.class.DoesNotExist");
+ fail();
+ } catch (ClassNotFoundException expected) {
+ }
+ }
+
+ public void testNewInstancePrivateConstructor() throws Exception {
+ try {
+ Class.forName(packageName + ".ClassWithPrivateConstructor").newInstance();
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+ }
+
+ public void testGetDeclaredMethod() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("method", (Class[]) null);
+ method.invoke(new OldAndroidClassTest(), (Object[]) null);
+ }
+
+ public void testGetDeclaredMethodWithArgs() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("methodWithArgs", Object.class);
+
+ Object invokeArgs[] = new Object[1];
+ invokeArgs[0] = "Hello";
+ Object ret = method.invoke(new OldAndroidClassTest(), invokeArgs);
+ assertEquals(ret, invokeArgs[0]);
+ }
+
+ public void testGetDeclaredMethodPrivate() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Method method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null);
+ method.invoke(new OldAndroidClassTest(), (Object[]) null);
+ }
+
+ public void testGetSuperclass() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Class objectClass = Class.forName("java.lang.Object");
+ assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass);
+ }
+
+ public void testIsAssignableFrom() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Class objectClass = Class.forName("java.lang.Object");
+ assertTrue(objectClass.isAssignableFrom(helloClass));
+ assertFalse(helloClass.isAssignableFrom(objectClass));
+ }
+
+ public void testGetConstructor() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ Constructor constructor = helloClass.getConstructor((Class[]) null);
+ assertNotNull(constructor);
+ }
+
+ public void testGetModifiers() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ assertTrue(Modifier.isPublic(helloClass.getModifiers()));
+ }
+
+ public void testGetMethod() throws Exception {
+ Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
+ helloClass.getMethod("method", (Class[]) null);
+ try {
+ Class[] argTypes = new Class[1];
+ argTypes[0] = helloClass;
+ helloClass.getMethod("method", argTypes);
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=14
+ public void testFieldSet() throws Exception {
+ OldAndroidClassTest.SimpleClass obj = new OldAndroidClassTest.SimpleClass();
+ Field field = obj.getClass().getDeclaredField("str");
+ field.set(obj, null);
+ }
+
+ public class SimpleClass {
+ public String str;
+ }
+
+ public Object methodWithArgs(Object o) {
+ return o;
+ }
+
+ boolean methodInvoked;
+
+ public void method() {
+ methodInvoked = true;
+ }
+
+ boolean privateMethodInvoked;
+
+ public void privateMethod() {
+ privateMethodInvoked = true;
+ }
+
+ // Regression for 1018067: Class.getMethods() returns the same method over
+ // and over again from all base classes
+ public void testClassGetMethodsNoDupes() {
+ Method[] methods = ArrayList.class.getMethods();
+ Set<String> set = new HashSet<String>();
+
+ for (Method method : methods) {
+ String signature = method.toString();
+
+ int par = signature.indexOf('(');
+ int dot = signature.lastIndexOf('.', par);
+
+ signature = signature.substring(dot + 1);
+
+ assertFalse("Duplicate " + signature, set.contains(signature));
+ set.add(signature);
+ }
+ }
+
+ interface MyInterface {
+ void foo();
+ }
+
+ interface MyOtherInterface extends MyInterface {
+ void bar();
+ }
+
+ abstract class MyClass implements MyOtherInterface {
+ public void gabba() {
+ }
+
+ public void hey() {
+ }
+ }
+
+ // Check if we also reflect methods from interfaces
+ public void testGetMethodsInterfaces() {
+ Method[] methods = MyInterface.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+
+ methods = MyOtherInterface.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+ assertTrue(hasMethod(methods, ".bar("));
+
+ methods = MyClass.class.getMethods();
+ assertTrue(hasMethod(methods, ".foo("));
+ assertTrue(hasMethod(methods, ".bar("));
+
+ assertTrue(hasMethod(methods, ".gabba("));
+ assertTrue(hasMethod(methods, ".hey("));
+
+ assertTrue(hasMethod(methods, ".toString("));
+ }
+
+ private boolean hasMethod(Method[] methods, String signature) {
+ for (Method method : methods) {
+ if (method.toString().contains(signature)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Test for Class.getPackage();
+ public void testClassGetPackage() {
+ assertNotNull(getClass().getPackage());
+ assertEquals(packageName, getClass().getPackage().getName());
+ assertEquals("Unknown", getClass().getPackage().getSpecificationTitle());
+
+ Package p = Object.class.getPackage();
+ assertNotNull(p);
+ assertEquals("java.lang", p.getName());
+ assertSame(p, Object.class.getPackage());
+ }
+
+ // Regression test for #1123708: Problem with getCanonicalName(),
+ // getSimpleName(), and getPackage().
+ //
+ // A couple of interesting cases need to be checked: Top-level classes,
+ // member classes, local classes, and anonymous classes. Also, boundary
+ // cases with '$' in the class names are checked, since the '$' is used
+ // as the separator between outer and inner class, so this might lead
+ // to problems (it did in the previous implementation).
+ //
+ // Caution: Adding local or anonymous classes elsewhere in this
+ // file might affect the test.
+ private class MemberClass {
+ }
+
+ private class Mi$o$oup {
+ }
+
+ public void testVariousClassNames() {
+ Class<?> clazz = this.getClass();
+ String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + ".");
+
+ // Simple, top-level class
+
+ assertEquals(pkg + "OldAndroidClassTest", clazz.getName());
+ assertEquals("OldAndroidClassTest", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest", clazz.getCanonicalName());
+
+ clazz = MemberClass.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$MemberClass", clazz.getName());
+ assertEquals("MemberClass", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest.MemberClass", clazz.getCanonicalName());
+
+ class LocalClass {
+ // This space intentionally left blank.
+ }
+
+ clazz = LocalClass.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$1LocalClass", clazz.getName());
+ assertEquals("LocalClass", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+
+ clazz = new Object() { }.getClass();
+
+ assertEquals(pkg + "OldAndroidClassTest$1", clazz.getName());
+ assertEquals("", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+
+ // Weird special cases with dollar in name.
+
+ clazz = Mou$$aka.class;
+
+ assertEquals(pkg + "Mou$$aka", clazz.getName());
+ assertEquals("Mou$$aka", clazz.getSimpleName());
+ assertEquals(pkg + "Mou$$aka", clazz.getCanonicalName());
+
+ clazz = Mi$o$oup.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$Mi$o$oup", clazz.getName());
+ assertEquals("Mi$o$oup", clazz.getSimpleName());
+ assertEquals(pkg + "OldAndroidClassTest.Mi$o$oup", clazz.getCanonicalName());
+
+ class Ma$hedPotatoe$ {
+ }
+
+ clazz = Ma$hedPotatoe$.class;
+
+ assertEquals(pkg + "OldAndroidClassTest$1Ma$hedPotatoe$", clazz.getName());
+ assertEquals("Ma$hedPotatoe$", clazz.getSimpleName());
+ assertNull(clazz.getCanonicalName());
+ }
+
+ public void testLocalMemberClass() {
+ Class<?> clazz = this.getClass();
+
+ assertFalse(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+
+ clazz = MemberClass.class;
+
+ assertTrue(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+
+ class OtherLocalClass {
+ }
+
+ clazz = OtherLocalClass.class;
+
+ assertFalse(clazz.isMemberClass());
+ assertTrue(clazz.isLocalClass());
+
+ clazz = new Object() { }.getClass();
+
+ assertFalse(clazz.isMemberClass());
+ assertFalse(clazz.isLocalClass());
+ }
+}
+
+class ClassWithPrivateConstructor {
+ private ClassWithPrivateConstructor() {
+ }
+}
+
+class Mou$$aka {
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/OldGenericReflectionCornerCases.java b/luni/src/test/java/libcore/java/lang/reflect/OldGenericReflectionCornerCases.java
index 907b8eb..168a00d 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/OldGenericReflectionCornerCases.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/OldGenericReflectionCornerCases.java
@@ -16,7 +16,6 @@
package libcore.java.lang.reflect;
-import dalvik.annotation.KnownFailure;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -122,7 +121,6 @@
void multipleBoundedWildcardUnEquality(Pair<? extends T, ? super T> param) {}
}
@SuppressWarnings("unchecked")
- @KnownFailure("Fails in CTS but passes under run-core-tests")
public void testMultipleBoundedWildcardUnEquality() throws Exception {
Class<? extends MultipleBoundedWildcardUnEquality> clazz = MultipleBoundedWildcardUnEquality.class;
@@ -178,7 +176,6 @@
void multipleBoundedWildcardEquality(Pair<? extends T, ? extends T> param) {}
}
@SuppressWarnings("unchecked")
- @KnownFailure("Fails in CTS but passes under run-core-tests")
public void testMultipleBoundedWildcard() throws Exception {
Class<? extends MultipleBoundedWildcardEquality> clazz = MultipleBoundedWildcardEquality.class;
diff --git a/luni/src/test/java/libcore/java/lang/reflect/OldGenericTypesTest.java b/luni/src/test/java/libcore/java/lang/reflect/OldGenericTypesTest.java
index f93b683..69eff4f 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/OldGenericTypesTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/OldGenericTypesTest.java
@@ -16,7 +16,6 @@
package libcore.java.lang.reflect;
-import dalvik.annotation.KnownFailure;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
@@ -160,7 +159,6 @@
assertEquals(typeVariableT, boundS);
}
@SuppressWarnings("unchecked")
- @KnownFailure("Fails in CTS but passes under run-core-tests")
public void testSimpleInheritance() throws Exception {
Class<? extends SimpleInheritance> clazz = SimpleInheritance.class;
TypeVariable<Class> subTypeVariable = getTypeParameter(clazz);
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
index 3b092e5..cdce405 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java
@@ -29,10 +29,10 @@
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
+import junit.framework.Assert;
import junit.framework.TestCase;
public final class ReflectionTest extends TestCase {
-
String classA = "libcore.java.lang.reflect.ReflectionTest$A";
String classB = "libcore.java.lang.reflect.ReflectionTest$B";
String classC = "libcore.java.lang.reflect.ReflectionTest$C";
@@ -45,6 +45,29 @@
AList.class.getGenericSuperclass().toString());
}
+ public void testClassGetName() {
+ assertEquals("int", int.class.getName());
+ assertEquals("[I", int[].class.getName());
+ assertEquals("java.lang.String", String.class.getName());
+ assertEquals("[Ljava.lang.String;", String[].class.getName());
+ assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getName());
+ assertEquals(getClass().getName() + "$A", A.class.getName());
+ assertEquals(getClass().getName() + "$B", B.class.getName());
+ assertEquals(getClass().getName() + "$DefinesMember", DefinesMember.class.getName());
+ }
+
+ public void testClassGetCanonicalName() {
+ assertEquals("int", int.class.getCanonicalName());
+ assertEquals("int[]", int[].class.getCanonicalName());
+ assertEquals("java.lang.String", String.class.getCanonicalName());
+ assertEquals("java.lang.String[]", String[].class.getCanonicalName());
+ assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getCanonicalName());
+ assertEquals(getClass().getName() + ".A", A.class.getCanonicalName());
+ assertEquals(getClass().getName() + ".B", B.class.getCanonicalName());
+ assertEquals(getClass().getName() + ".DefinesMember",
+ DefinesMember.class.getCanonicalName());
+ }
+
public void testFieldToString() throws Exception {
Field fieldOne = C.class.getDeclaredField("fieldOne");
String fieldOneRaw = "public static " + classA + " " + classC + ".fieldOne";
@@ -254,6 +277,28 @@
assertEquals(1, count(names(fields), "field"));
}
+ /**
+ * Class.isEnum() erroneously returned true for indirect descendants of
+ * Enum. http://b/1062200.
+ */
+ public void testClassIsEnum() {
+ Class<?> trafficClass = TrafficLights.class;
+ Class<?> redClass = TrafficLights.RED.getClass();
+ Class<?> yellowClass = TrafficLights.YELLOW.getClass();
+ Class<?> greenClass = TrafficLights.GREEN.getClass();
+ assertSame(trafficClass, redClass);
+ assertNotSame(trafficClass, yellowClass);
+ assertNotSame(trafficClass, greenClass);
+ assertNotSame(yellowClass, greenClass);
+ assertTrue(trafficClass.isEnum());
+ assertTrue(redClass.isEnum());
+ assertFalse(yellowClass.isEnum());
+ assertFalse(greenClass.isEnum());
+ assertNotNull(trafficClass.getEnumConstants());
+ assertNull(yellowClass.getEnumConstants());
+ assertNull(greenClass.getEnumConstants());
+ }
+
static class A {}
static class AList extends ArrayList<A> {}
@@ -319,4 +364,15 @@
}
return result;
}
+
+ enum TrafficLights {
+ RED,
+ YELLOW {},
+ GREEN {
+ @SuppressWarnings("unused")
+ int i;
+ @SuppressWarnings("unused")
+ void foobar() {}
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
index 726b05a..d33c5f3 100644
--- a/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
+++ b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
@@ -62,6 +62,21 @@
}
}
+ public void test_connect_timeout() throws Exception {
+ StuckServer ss = new StuckServer();
+ Socket s = new Socket();
+ new Killer(s).start();
+ try {
+ System.err.println("connect (with timeout)...");
+ s.connect(ss.getLocalSocketAddress(), 3600 * 1000);
+ fail("connect returned!");
+ } catch (SocketException expected) {
+ assertEquals("Socket closed", expected.getMessage());
+ } finally {
+ ss.close();
+ }
+ }
+
public void test_connect_nonBlocking() throws Exception {
StuckServer ss = new StuckServer();
SocketChannel s = SocketChannel.open();
diff --git a/luni/src/test/java/libcore/java/net/CookiesTest.java b/luni/src/test/java/libcore/java/net/CookiesTest.java
index a661673..f14a91e 100644
--- a/luni/src/test/java/libcore/java/net/CookiesTest.java
+++ b/luni/src/test/java/libcore/java/net/CookiesTest.java
@@ -53,7 +53,7 @@
server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
+ "expires=Fri, 31-Dec-9999 23:59:59 GMT; "
+ "path=/path; "
- + "domain=.local; "
+ + "domain=" + server.getCookieDomain() + "; "
+ "secure"));
get(server, "/path/foo");
@@ -65,7 +65,7 @@
assertEquals(null, cookie.getComment());
assertEquals(null, cookie.getCommentURL());
assertEquals(false, cookie.getDiscard());
- assertEquals(".local", cookie.getDomain());
+ assertEquals(server.getCookieDomain(), cookie.getDomain());
assertTrue(cookie.getMaxAge() > 100000000000L);
assertEquals("/path", cookie.getPath());
assertEquals(true, cookie.getSecure());
@@ -80,7 +80,7 @@
server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
+ "Comment=this cookie is delicious; "
- + "Domain=.local; "
+ + "Domain=" + server.getCookieDomain() + "; "
+ "Max-Age=60; "
+ "Path=/path; "
+ "Secure; "
@@ -95,7 +95,7 @@
assertEquals("this cookie is delicious", cookie.getComment());
assertEquals(null, cookie.getCommentURL());
assertEquals(false, cookie.getDiscard());
- assertEquals(".local", cookie.getDomain());
+ assertEquals(server.getCookieDomain(), cookie.getDomain());
assertEquals(60, cookie.getMaxAge());
assertEquals("/path", cookie.getPath());
assertEquals(true, cookie.getSecure());
@@ -112,7 +112,7 @@
+ "Comment=this cookie is delicious; "
+ "CommentURL=http://google.com/; "
+ "Discard; "
- + "Domain=.local; "
+ + "Domain=" + server.getCookieDomain() + "; "
+ "Max-Age=60; "
+ "Path=/path; "
+ "Port=\"80,443," + server.getPort() + "\"; "
@@ -128,7 +128,7 @@
assertEquals("this cookie is delicious", cookie.getComment());
assertEquals("http://google.com/", cookie.getCommentURL());
assertEquals(true, cookie.getDiscard());
- assertEquals(".local", cookie.getDomain());
+ assertEquals(server.getCookieDomain(), cookie.getDomain());
assertEquals(60, cookie.getMaxAge());
assertEquals("/path", cookie.getPath());
assertEquals("80,443," + server.getPort(), cookie.getPortlist());
@@ -146,7 +146,7 @@
+ "Comment=\"this cookie is delicious\"; "
+ "CommentURL=\"http://google.com/\"; "
+ "Discard; "
- + "Domain=\".local\"; "
+ + "Domain=\"" + server.getCookieDomain() + "\"; "
+ "Max-Age=\"60\"; "
+ "Path=\"/path\"; "
+ "Port=\"80,443," + server.getPort() + "\"; "
@@ -162,7 +162,7 @@
assertEquals("this cookie is delicious", cookie.getComment());
assertEquals("http://google.com/", cookie.getCommentURL());
assertEquals(true, cookie.getDiscard());
- assertEquals(".local", cookie.getDomain());
+ assertEquals(server.getCookieDomain(), cookie.getDomain());
assertEquals(60, cookie.getMaxAge());
assertEquals("/path", cookie.getPath());
assertEquals("80,443," + server.getPort(), cookie.getPortlist());
@@ -250,11 +250,11 @@
CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
HttpCookie cookieA = new HttpCookie("a", "android");
- cookieA.setDomain(".local");
+ cookieA.setDomain(server.getCookieDomain());
cookieA.setPath("/");
cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieA);
HttpCookie cookieB = new HttpCookie("b", "banana");
- cookieB.setDomain(".local");
+ cookieB.setDomain(server.getCookieDomain());
cookieB.setPath("/");
cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieB);
CookieHandler.setDefault(cookieManager);
@@ -264,8 +264,8 @@
List<String> receivedHeaders = request.getHeaders();
assertContains(receivedHeaders, "Cookie: $Version=\"1\"; "
- + "a=\"android\";$Path=\"/\";$Domain=\".local\"; "
- + "b=\"banana\";$Path=\"/\";$Domain=\".local\"");
+ + "a=\"android\";$Path=\"/\";$Domain=\"" + server.getCookieDomain() + "\"; "
+ + "b=\"banana\";$Path=\"/\";$Domain=\"" + server.getCookieDomain() + "\"");
}
public void testRedirectsDoNotIncludeTooManyCookies() throws Exception {
@@ -281,7 +281,7 @@
CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
HttpCookie cookie = new HttpCookie("c", "cookie");
- cookie.setDomain(".local");
+ cookie.setDomain(redirectSource.getCookieDomain());
cookie.setPath("/");
String portList = Integer.toString(redirectSource.getPort());
cookie.setPortlist(portList);
@@ -292,7 +292,8 @@
RecordedRequest request = redirectSource.takeRequest();
assertContains(request.getHeaders(), "Cookie: $Version=\"1\"; "
- + "c=\"cookie\";$Path=\"/\";$Domain=\".local\";$Port=\"" + portList + "\"");
+ + "c=\"cookie\";$Path=\"/\";$Domain=\"" + redirectSource.getCookieDomain()
+ + "\";$Port=\"" + portList + "\"");
for (String header : redirectTarget.takeRequest().getHeaders()) {
if (header.startsWith("Cookie")) {
@@ -308,7 +309,7 @@
* manager should show up in the request and in {@code
* getRequestProperties}.
*/
- public void testHeadersSentToCookieHandler() throws IOException, InterruptedException {
+ public void testHeadersSentToCookieHandler() throws IOException, InterruptedException {
final Map<String, List<String>> cookieHandlerHeaders = new HashMap<String, List<String>>();
CookieHandler.setDefault(new CookieManager() {
@Override public Map<String, List<String>> get(URI uri,
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 36ea464..edca1a6 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -16,19 +16,13 @@
package libcore.java.net;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Collections;
-import tests.util.SerializationTester;
+import libcore.util.SerializationTester;
public class InetAddressTest extends junit.framework.TestCase {
private static final byte[] LOOPBACK6_BYTES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
@@ -138,11 +132,23 @@
public void test_isReachable() throws Exception {
// http://code.google.com/p/android/issues/detail?id=20203
- InetAddress addr = SerializationTester.getDeserializedObject(InetAddress.getByName("www.google.com"));
- addr.isReachable(500);
- for (NetworkInterface nif : Collections.list(NetworkInterface.getNetworkInterfaces())) {
- addr.isReachable(nif, 20, 500);
- }
+ String s = "aced0005737200146a6176612e6e65742e496e6574416464726573732d9b57af"
+ + "9fe3ebdb0200034900076164647265737349000666616d696c794c0008686f737"
+ + "44e616d657400124c6a6176612f6c616e672f537472696e673b78704a7d9d6300"
+ + "00000274000e7777772e676f6f676c652e636f6d";
+ InetAddress inetAddress = InetAddress.getByName("www.google.com");
+ new SerializationTester<InetAddress>(inetAddress, s) {
+ @Override protected void verify(InetAddress deserialized) throws Exception {
+ deserialized.isReachable(500);
+ for (NetworkInterface nif
+ : Collections.list(NetworkInterface.getNetworkInterfaces())) {
+ deserialized.isReachable(nif, 20, 500);
+ }
+ }
+ @Override protected boolean equals(InetAddress a, InetAddress b) {
+ return a.getHostName().equals(b.getHostName());
+ }
+ }.test();
}
public void test_isSiteLocalAddress() throws Exception {
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index e796e1e..42b7250 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -248,6 +248,44 @@
server.shutdown();
}
+ // http://b/5534202
+ public void testAvailable() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ assertAvailableReturnsZeroAfterSocketReadsAllData();
+ System.out.println("Success on rep " + i);
+ }
+ }
+
+ private void assertAvailableReturnsZeroAfterSocketReadsAllData() throws Exception {
+ final byte[] data = "foo".getBytes();
+ final ServerSocket serverSocket = new ServerSocket(0);
+
+ new Thread() {
+ @Override public void run() {
+ try {
+ Socket socket = serverSocket.accept();
+ socket.getOutputStream().write(data);
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+
+ Socket socket = new Socket("localhost", serverSocket.getLocalPort());
+ byte[] readBuffer = new byte[128];
+ InputStream in = socket.getInputStream();
+ int total = 0;
+ // to prevent available() from cheating after EOF, stop reading before -1 is returned
+ while (total < data.length) {
+ total += in.read(readBuffer);
+ }
+ assertEquals(0, in.available());
+
+ socket.close();
+ serverSocket.close();
+ }
+
static class MockServer {
private ExecutorService executor;
private ServerSocket serverSocket;
diff --git a/luni/src/test/java/libcore/java/net/URITest.java b/luni/src/test/java/libcore/java/net/URITest.java
index d45facc..b37358c 100644
--- a/luni/src/test/java/libcore/java/net/URITest.java
+++ b/luni/src/test/java/libcore/java/net/URITest.java
@@ -19,7 +19,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public final class URITest extends TestCase {
@@ -67,7 +67,7 @@
+ "77400124c6a6176612f6c616e672f537472696e673b787074002a687474703a2f2f757365723a706"
+ "1737340686f73742f706174682f66696c653f7175657279236861736878";
URI uri = new URI("http://user:pass@host/path/file?query#hash");
- new SerializableTester<URI>(uri, s).test();
+ new SerializationTester<URI>(uri, s).test();
}
public void testEmptyHost() throws Exception {
@@ -621,5 +621,43 @@
assertEquals(new URI(""), relative.relativize(relative));
}
+ public void testPartContainsSpace() throws Exception {
+ try {
+ new URI("ht tp://host/");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://user name@host/");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://ho st/");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://host:80 80/");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://host/fi le");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://host/file?que ry");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ try {
+ new URI("http://host/file?query#re f");
+ fail();
+ } catch (URISyntaxException expected) {
+ }
+ }
+
// Adding a new test? Consider adding an equivalent test to URLTest.java
}
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 1305a81..347242a 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -25,6 +25,7 @@
import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END;
import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -34,6 +35,7 @@
import java.net.ConnectException;
import java.net.HttpRetryException;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.ProtocolException;
import java.net.Proxy;
@@ -42,16 +44,24 @@
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
+import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
@@ -68,20 +78,12 @@
import junit.framework.TestCase;
import libcore.java.security.TestKeyStore;
import libcore.javax.net.ssl.TestSSLContext;
+import libcore.net.http.HttpResponseCache;
import tests.net.StuckServer;
public final class URLConnectionTest extends TestCase {
-
- private static final Authenticator SIMPLE_AUTHENTICATOR = new Authenticator() {
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication("username", "password".toCharArray());
- }
- };
-
- /** base64("username:password") */
- private static final String BASE_64_CREDENTIALS = "dXNlcm5hbWU6cGFzc3dvcmQ=";
-
private MockWebServer server = new MockWebServer();
+ private HttpResponseCache cache;
private String hostName;
@Override protected void setUp() throws Exception {
@@ -99,6 +101,9 @@
System.clearProperty("https.proxyHost");
System.clearProperty("https.proxyPort");
server.shutdown();
+ if (cache != null) {
+ cache.getCache().delete();
+ }
super.tearDown();
}
@@ -275,24 +280,36 @@
assertEquals(2, server.takeRequest().getSequenceNumber());
}
+ /**
+ * Test that connections are added to the pool as soon as the response has
+ * been consumed.
+ */
+ public void testConnectionsArePooledWithoutExplicitDisconnect() throws Exception {
+ server.enqueue(new MockResponse().setBody("ABC"));
+ server.enqueue(new MockResponse().setBody("DEF"));
+ server.play();
+
+ URLConnection connection1 = server.getUrl("/").openConnection();
+ assertEquals("ABC", readAscii(connection1.getInputStream(), Integer.MAX_VALUE));
+ assertEquals(0, server.takeRequest().getSequenceNumber());
+ URLConnection connection2 = server.getUrl("/").openConnection();
+ assertEquals("DEF", readAscii(connection2.getInputStream(), Integer.MAX_VALUE));
+ assertEquals(1, server.takeRequest().getSequenceNumber());
+ }
+
public void testServerClosesSocket() throws Exception {
- testServerClosesOutput(DISCONNECT_AT_END);
+ testServerClosesSocket(DISCONNECT_AT_END);
}
public void testServerShutdownInput() throws Exception {
- testServerClosesOutput(SHUTDOWN_INPUT_AT_END);
+ testServerClosesSocket(SHUTDOWN_INPUT_AT_END);
}
- public void testServerShutdownOutput() throws Exception {
- testServerClosesOutput(SHUTDOWN_OUTPUT_AT_END);
- }
-
- private void testServerClosesOutput(SocketPolicy socketPolicy) throws Exception {
+ private void testServerClosesSocket(SocketPolicy socketPolicy) throws Exception {
server.enqueue(new MockResponse()
.setBody("This connection won't pool properly")
.setSocketPolicy(socketPolicy));
- server.enqueue(new MockResponse()
- .setBody("This comes after a busted connection"));
+ server.enqueue(new MockResponse().setBody("This comes after a busted connection"));
server.play();
assertContent("This connection won't pool properly", server.getUrl("/a").openConnection());
@@ -302,6 +319,55 @@
assertEquals(0, server.takeRequest().getSequenceNumber());
}
+ public void testServerShutdownOutput() throws Exception {
+ // This test causes MockWebServer to log a "connection failed" stack trace
+ server.enqueue(new MockResponse()
+ .setBody("Output shutdown after this response")
+ .setSocketPolicy(SHUTDOWN_OUTPUT_AT_END));
+ server.enqueue(new MockResponse().setBody("This response will fail to write"));
+ server.enqueue(new MockResponse().setBody("This comes after a busted connection"));
+ server.play();
+
+ assertContent("Output shutdown after this response", server.getUrl("/a").openConnection());
+ assertEquals(0, server.takeRequest().getSequenceNumber());
+ assertContent("This comes after a busted connection", server.getUrl("/b").openConnection());
+ assertEquals(1, server.takeRequest().getSequenceNumber());
+ assertEquals(0, server.takeRequest().getSequenceNumber());
+ }
+
+ public void testRetryableRequestBodyAfterBrokenConnection() throws Exception {
+ server.enqueue(new MockResponse().setBody("abc").setSocketPolicy(DISCONNECT_AT_END));
+ server.enqueue(new MockResponse().setBody("def"));
+ server.play();
+
+ assertContent("abc", server.getUrl("/a").openConnection());
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/b").openConnection();
+ connection.setDoOutput(true);
+ OutputStream out = connection.getOutputStream();
+ out.write(new byte[] {1, 2, 3});
+ out.close();
+ assertContent("def", connection);
+ }
+
+ public void testNonRetryableRequestBodyAfterBrokenConnection() throws Exception {
+ server.enqueue(new MockResponse().setBody("abc").setSocketPolicy(DISCONNECT_AT_END));
+ server.enqueue(new MockResponse().setBody("def"));
+ server.play();
+
+ assertContent("abc", server.getUrl("/a").openConnection());
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/b").openConnection();
+ connection.setDoOutput(true);
+ connection.setFixedLengthStreamingMode(3);
+ OutputStream out = connection.getOutputStream();
+ out.write(new byte[] {1, 2, 3});
+ out.close();
+ try {
+ connection.getInputStream();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
enum WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS }
public void test_chunkedUpload_byteByByte() throws Exception {
@@ -396,10 +462,12 @@
RecordedRequest request = server.takeRequest();
assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
+ assertEquals("TLSv1", request.getSslProtocol());
}
public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
+ SSLSocketFactory clientSocketFactory = testSSLContext.clientContext.getSocketFactory();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
@@ -407,11 +475,11 @@
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ connection.setSSLSocketFactory(clientSocketFactory);
assertContent("this response comes via HTTPS", connection);
connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ connection.setSSLSocketFactory(clientSocketFactory);
assertContent("another response via HTTPS", connection);
assertEquals(0, server.takeRequest().getSequenceNumber());
@@ -609,6 +677,50 @@
assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls);
}
+
+ /**
+ * Tolerate bad https proxy response when using HttpResponseCache. http://b/6754912
+ */
+ public void testConnectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache() throws Exception {
+ ProxyConfig proxyConfig = ProxyConfig.PROXY_SYSTEM_PROPERTY;
+
+ TestSSLContext testSSLContext = TestSSLContext.create();
+
+ initResponseCache();
+
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
+ server.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
+ .clearHeaders()
+ .setBody("bogus proxy connect response content")); // Key to reproducing b/6754912
+ server.play();
+
+ URL url = new URL("https://android.com/foo");
+ HttpsURLConnection connection = (HttpsURLConnection) proxyConfig.connect(server, url);
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+
+ try {
+ connection.connect();
+ fail();
+ } catch (IOException expected) {
+ // Thrown when the connect causes SSLSocket.startHandshake() to throw
+ // when it sees the "bogus proxy connect response content"
+ // instead of a ServerHello handshake message.
+ }
+
+ RecordedRequest connect = server.takeRequest();
+ assertEquals("Connect line failure on proxy",
+ "CONNECT android.com:443 HTTP/1.1", connect.getRequestLine());
+ assertContains(connect.getHeaders(), "Host: android.com");
+ }
+
+ private void initResponseCache() throws IOException {
+ String tmp = System.getProperty("java.io.tmpdir");
+ File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
+ cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
+ ResponseCache.setDefault(cache);
+ }
+
/**
* Test which headers are sent unencrypted to the HTTP proxy.
*/
@@ -647,7 +759,7 @@
}
public void testProxyAuthenticateOnConnect() throws Exception {
- Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
+ Authenticator.setDefault(new SimpleAuthenticator());
TestSSLContext testSSLContext = TestSSLContext.create();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
server.enqueue(new MockResponse()
@@ -672,7 +784,8 @@
RecordedRequest connect2 = server.takeRequest();
assertEquals("CONNECT android.com:443 HTTP/1.1", connect2.getRequestLine());
- assertContains(connect2.getHeaders(), "Proxy-Authorization: Basic " + BASE_64_CREDENTIALS);
+ assertContains(connect2.getHeaders(), "Proxy-Authorization: Basic "
+ + SimpleAuthenticator.BASE_64_CREDENTIALS);
RecordedRequest get = server.takeRequest();
assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
@@ -767,7 +880,7 @@
*/
public void testUnauthorizedResponseHandling() throws IOException {
MockResponse response = new MockResponse()
- .addHeader("WWW-Authenticate: challenge")
+ .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
.setResponseCode(401) // UNAUTHORIZED
.setBody("Unauthorized");
server.enqueue(response);
@@ -899,6 +1012,29 @@
}
/**
+ * Test that HEAD requests don't have a body regardless of the response
+ * headers. http://code.google.com/p/android/issues/detail?id=24672
+ */
+ public void testHeadAndContentLength() throws Exception {
+ server.enqueue(new MockResponse()
+ .clearHeaders()
+ .addHeader("Content-Length: 100"));
+ server.enqueue(new MockResponse().setBody("A"));
+ server.play();
+
+ HttpURLConnection connection1 = (HttpURLConnection) server.getUrl("/").openConnection();
+ connection1.setRequestMethod("HEAD");
+ assertEquals("100", connection1.getHeaderField("Content-Length"));
+ assertContent("", connection1);
+
+ HttpURLConnection connection2 = (HttpURLConnection) server.getUrl("/").openConnection();
+ assertEquals("A", readAscii(connection2.getInputStream(), Integer.MAX_VALUE));
+
+ assertEquals(0, server.takeRequest().getSequenceNumber());
+ assertEquals(1, server.takeRequest().getSequenceNumber());
+ }
+
+ /**
* Obnoxiously test that the chunk sizes transmitted exactly equal the
* requested data+chunk header size. Although setChunkedStreamingMode()
* isn't specific about whether the size applies to the data or the
@@ -936,7 +1072,7 @@
server.enqueue(pleaseAuthenticate);
server.play();
- Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
+ Authenticator.setDefault(new SimpleAuthenticator());
HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
connection.setDoOutput(true);
byte[] requestBody = { 'A', 'B', 'C', 'D' };
@@ -1117,7 +1253,7 @@
server.enqueue(new MockResponse().setBody("Successful auth!"));
server.play();
- Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
+ Authenticator.setDefault(new SimpleAuthenticator());
HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
connection.setDoOutput(true);
byte[] requestBody = { 'A', 'B', 'C', 'D' };
@@ -1128,13 +1264,14 @@
// no authorization header for the first request...
RecordedRequest request = server.takeRequest();
- assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*");
+ assertContainsNoneMatching(request.getHeaders(), "Authorization: .*");
// ...but the three requests that follow include an authorization header
for (int i = 0; i < 3; i++) {
request = server.takeRequest();
assertEquals("POST / HTTP/1.1", request.getRequestLine());
- assertContains(request.getHeaders(), "Authorization: Basic " + BASE_64_CREDENTIALS);
+ assertContains(request.getHeaders(), "Authorization: Basic "
+ + SimpleAuthenticator.BASE_64_CREDENTIALS);
assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody()));
}
}
@@ -1152,22 +1289,74 @@
server.enqueue(new MockResponse().setBody("Successful auth!"));
server.play();
- Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
+ SimpleAuthenticator authenticator = new SimpleAuthenticator();
+ Authenticator.setDefault(authenticator);
HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+ assertEquals(Authenticator.RequestorType.SERVER, authenticator.requestorType);
+ assertEquals(server.getPort(), authenticator.requestingPort);
+ assertEquals(InetAddress.getByName(server.getHostName()), authenticator.requestingSite);
+ assertEquals("protected area", authenticator.requestingPrompt);
+ assertEquals("http", authenticator.requestingProtocol);
+ assertEquals("Basic", authenticator.requestingScheme);
// no authorization header for the first request...
RecordedRequest request = server.takeRequest();
- assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*");
+ assertContainsNoneMatching(request.getHeaders(), "Authorization: .*");
// ...but the three requests that follow requests include an authorization header
for (int i = 0; i < 3; i++) {
request = server.takeRequest();
assertEquals("GET / HTTP/1.1", request.getRequestLine());
- assertContains(request.getHeaders(), "Authorization: Basic " + BASE_64_CREDENTIALS);
+ assertContains(request.getHeaders(), "Authorization: Basic "
+ + SimpleAuthenticator.BASE_64_CREDENTIALS);
}
}
+ // http://code.google.com/p/android/issues/detail?id=19081
+ public void testAuthenticateWithCommaSeparatedAuthenticationMethods() throws Exception {
+ server.enqueue(new MockResponse()
+ .setResponseCode(401)
+ .addHeader("WWW-Authenticate: Scheme1 realm=\"a\", Scheme2 realm=\"b\", "
+ + "Scheme3 realm=\"c\"")
+ .setBody("Please authenticate."));
+ server.enqueue(new MockResponse().setBody("Successful auth!"));
+ server.play();
+
+ SimpleAuthenticator authenticator = new SimpleAuthenticator();
+ authenticator.expectedPrompt = "b";
+ Authenticator.setDefault(authenticator);
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+ assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+
+ assertContainsNoneMatching(server.takeRequest().getHeaders(), "Authorization: .*");
+ assertContains(server.takeRequest().getHeaders(),
+ "Authorization: Scheme2 " + SimpleAuthenticator.BASE_64_CREDENTIALS);
+ assertEquals("Scheme2", authenticator.requestingScheme);
+ }
+
+ public void testAuthenticateWithMultipleAuthenticationHeaders() throws Exception {
+ server.enqueue(new MockResponse()
+ .setResponseCode(401)
+ .addHeader("WWW-Authenticate: Scheme1 realm=\"a\"")
+ .addHeader("WWW-Authenticate: Scheme2 realm=\"b\"")
+ .addHeader("WWW-Authenticate: Scheme3 realm=\"c\"")
+ .setBody("Please authenticate."));
+ server.enqueue(new MockResponse().setBody("Successful auth!"));
+ server.play();
+
+ SimpleAuthenticator authenticator = new SimpleAuthenticator();
+ authenticator.expectedPrompt = "b";
+ Authenticator.setDefault(authenticator);
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+ assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+
+ assertContainsNoneMatching(server.takeRequest().getHeaders(), "Authorization: .*");
+ assertContains(server.takeRequest().getHeaders(),
+ "Authorization: Scheme2 " + SimpleAuthenticator.BASE_64_CREDENTIALS);
+ assertEquals("Scheme2", authenticator.requestingScheme);
+ }
+
public void testRedirectedWithChunkedEncoding() throws Exception {
testRedirected(TransferKind.CHUNKED, true);
}
@@ -1378,6 +1567,11 @@
}
}
+ /**
+ * Test that the timeout period is honored. The timeout may be doubled!
+ * HttpURLConnection will wait the full timeout for each of the server's IP
+ * addresses. This is typically one IPv4 address and one IPv6 address.
+ */
public void testConnectTimeouts() throws IOException {
StuckServer ss = new StuckServer();
int serverPort = ss.getLocalPort();
@@ -1389,8 +1583,10 @@
urlConnection.getInputStream();
fail();
} catch (SocketTimeoutException expected) {
- long actual = System.currentTimeMillis() - start;
- assertTrue(Math.abs(timeout - actual) < 500);
+ long elapsed = System.currentTimeMillis() - start;
+ int attempts = InetAddress.getAllByName("localhost").length; // one per IP address
+ assertTrue("timeout=" +timeout + ", elapsed=" + elapsed + ", attempts=" + attempts,
+ Math.abs((attempts * timeout) - elapsed) < 500);
} finally {
ss.close();
}
@@ -1895,6 +2091,57 @@
assertEquals(-1, in.read());
}
+ // http://code.google.com/p/android/issues/detail?id=28095
+ public void testInvalidIpv4Address() throws Exception {
+ try {
+ URI uri = new URI("http://1111.111.111.111/index.html");
+ uri.toURL().openConnection().connect();
+ fail();
+ } catch (UnknownHostException expected) {
+ }
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=16895
+ public void testUrlWithSpaceInHost() throws Exception {
+ URLConnection urlConnection = new URL("http://and roid.com/").openConnection();
+ try {
+ urlConnection.getInputStream();
+ fail();
+ } catch (UnknownHostException expected) {
+ }
+ }
+
+ public void testUrlWithSpaceInHostViaHttpProxy() throws Exception {
+ server.enqueue(new MockResponse());
+ server.play();
+ URLConnection urlConnection = new URL("http://and roid.com/")
+ .openConnection(server.toProxyAddress());
+ try {
+ urlConnection.getInputStream();
+ fail(); // the RI makes a bogus proxy request for "GET http://and roid.com/ HTTP/1.1"
+ } catch (UnknownHostException expected) {
+ }
+ }
+
+ public void testSslFallback() throws Exception {
+ TestSSLContext testSSLContext = TestSSLContext.create();
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
+ server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setBody("This required a 2nd handshake"));
+ server.play();
+
+ HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ assertEquals("This required a 2nd handshake",
+ readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+
+ RecordedRequest first = server.takeRequest();
+ assertEquals(0, first.getSequenceNumber());
+ RecordedRequest retry = server.takeRequest();
+ assertEquals(0, retry.getSequenceNumber());
+ assertEquals("SSLv3", retry.getSslProtocol());
+ }
+
public void testInspectSslBeforeConnect() throws Exception {
TestSSLContext testSSLContext = TestSSLContext.create();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
@@ -2101,4 +2348,29 @@
return true;
}
}
+
+ private static class SimpleAuthenticator extends Authenticator {
+ /** base64("username:password") */
+ private static final String BASE_64_CREDENTIALS = "dXNlcm5hbWU6cGFzc3dvcmQ=";
+
+ private String expectedPrompt;
+ private RequestorType requestorType;
+ private int requestingPort;
+ private InetAddress requestingSite;
+ private String requestingPrompt;
+ private String requestingProtocol;
+ private String requestingScheme;
+
+ protected PasswordAuthentication getPasswordAuthentication() {
+ requestorType = getRequestorType();
+ requestingPort = getRequestingPort();
+ requestingSite = getRequestingSite();
+ requestingPrompt = getRequestingPrompt();
+ requestingProtocol = getRequestingProtocol();
+ requestingScheme = getRequestingScheme();
+ return (expectedPrompt == null || expectedPrompt.equals(requestingPrompt))
+ ? new PasswordAuthentication("username", "password".toCharArray())
+ : null;
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index af5915a..ced8314 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -21,7 +21,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public final class URLTest extends TestCase {
@@ -103,7 +103,7 @@
+ "e00017870ffffffff74000e757365723a7061737340686f73747400102f706174682f66696c653f7"
+ "175657279740004686f7374740004687474707400046861736878";
URL url = new URL("http://user:pass@host/path/file?query#hash");
- new SerializableTester<URL>(url, s).test();
+ new SerializationTester<URL>(url, s).test();
}
/**
@@ -119,7 +119,7 @@
+ "47400102f706174682f66696c653f7175657279740004686f7374740004687474707400046861736"
+ "878";
final URL url = new URL("http://user:pass@host/path/file?query#hash");
- new SerializableTester<URL>(url, s) {
+ new SerializationTester<URL>(url, s) {
@Override protected void verify(URL deserialized) {
assertEquals(url.hashCode(), deserialized.hashCode());
}
@@ -668,5 +668,23 @@
assertEquals("", new URL("http", "host", -1, "", null).getPath());
}
+ public void testPartContainsSpace() throws Exception {
+ try {
+ new URL("ht tp://host/");
+ fail();
+ } catch (MalformedURLException expected) {
+ }
+ assertEquals("user name", new URL("http://user name@host/").getUserInfo());
+ assertEquals("ho st", new URL("http://ho st/").getHost());
+ try {
+ new URL("http://host:80 80/");
+ fail();
+ } catch (MalformedURLException expected) {
+ }
+ assertEquals("/fi le", new URL("http://host/fi le").getFile());
+ assertEquals("que ry", new URL("http://host/file?que ry").getQuery());
+ assertEquals("re f", new URL("http://host/file?query#re f").getRef());
+ }
+
// Adding a new test? Consider adding an equivalent test to URITest.java
}
diff --git a/luni/src/test/java/libcore/java/nio/BufferTest.java b/luni/src/test/java/libcore/java/nio/BufferTest.java
index 255db36..06a8e94 100644
--- a/luni/src/test/java/libcore/java/nio/BufferTest.java
+++ b/luni/src/test/java/libcore/java/nio/BufferTest.java
@@ -17,6 +17,7 @@
package libcore.java.nio;
import java.io.*;
+import java.lang.reflect.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.Arrays;
@@ -654,4 +655,24 @@
CharSequence cs = cb.subSequence(0, cb.length());
assertEquals("Hello", cs.toString());
}
+
+ public void testHasArrayOnJniDirectByteBuffer() throws Exception {
+ // Simulate a call to JNI's NewDirectByteBuffer.
+ Class<?> c = Class.forName("java.nio.ReadWriteDirectByteBuffer");
+ Constructor<?> ctor = c.getDeclaredConstructor(int.class, int.class);
+ ctor.setAccessible(true);
+ ByteBuffer bb = (ByteBuffer) ctor.newInstance(0, 0);
+
+ try {
+ bb.array();
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ try {
+ bb.arrayOffset();
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ assertFalse(bb.hasArray());
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
index aa958ad..f73b6d5 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
@@ -25,6 +25,8 @@
import java.nio.channels.SocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import libcore.io.Libcore;
+import libcore.io.OsConstants;
import junit.framework.TestCase;
import tests.net.StuckServer;
@@ -69,6 +71,25 @@
}
}
+ // http://b/6453247
+ // This test won't work on the host until/unless we start using libcorkscrew there.
+ // The runtime itself blocks SIGQUIT, so that doesn't cause poll(2) to EINTR directly.
+ // The EINTR is caused by the way libcorkscrew works.
+ public void testEINTR() throws Exception {
+ Selector selector = Selector.open();
+ new Thread(new Runnable() {
+ @Override public void run() {
+ try {
+ Thread.sleep(2000);
+ Libcore.os.kill(Libcore.os.getpid(), OsConstants.SIGQUIT);
+ } catch (Exception ex) {
+ fail();
+ }
+ }
+ }).start();
+ assertEquals(0, selector.select());
+ }
+
// http://code.google.com/p/android/issues/detail?id=15388
public void testInterrupted() throws IOException {
Selector selector = Selector.open();
diff --git a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
index be353cc..cc90147 100644
--- a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
@@ -16,17 +16,30 @@
package libcore.java.security;
+import java.math.BigInteger;
import java.security.Key;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import junit.framework.TestCase;
public class KeyPairGeneratorTest extends TestCase {
@@ -135,5 +148,125 @@
assertEquals(expectedAlgorithm, k.getAlgorithm().toUpperCase());
assertNotNull(k.getEncoded());
assertNotNull(k.getFormat());
+
+ test_KeyWithAllKeyFactories(k);
+ }
+
+ private void test_KeyWithAllKeyFactories(Key k) throws Exception {
+ byte[] encoded = k.getEncoded();
+
+ String keyAlgo = k.getAlgorithm();
+
+ Provider[] providers = Security.getProviders();
+ for (Provider p : providers) {
+ Set<Provider.Service> services = p.getServices();
+ for (Provider.Service service : services) {
+ if (!"KeyFactory".equals(service.getType())) {
+ continue;
+ }
+ if (!service.getAlgorithm().equals(keyAlgo)) {
+ continue;
+ }
+
+ if ("PKCS#8".equals(k.getFormat())) {
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
+ KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p);
+ PrivateKey privKey = kf.generatePrivate(spec);
+ assertNotNull(privKey);
+ assertTrue(Arrays.equals(privKey.getEncoded(), encoded));
+ } else if ("X.509".equals(k.getFormat())) {
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
+ KeyFactory kf = KeyFactory.getInstance(k.getAlgorithm(), p);
+ PublicKey pubKey = kf.generatePublic(spec);
+ assertNotNull(pubKey);
+ assertTrue(Arrays.equals(encoded, pubKey.getEncoded()));
+ }
+ }
+ }
+ }
+
+ private static final BigInteger DSA_P = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0x9e, (byte) 0x61, (byte) 0xc2, (byte) 0x89, (byte) 0xef, (byte) 0x77, (byte) 0xa9,
+ (byte) 0x4e, (byte) 0x13, (byte) 0x67, (byte) 0x64, (byte) 0x1f, (byte) 0x09, (byte) 0x01, (byte) 0xfe,
+ (byte) 0x24, (byte) 0x13, (byte) 0x53, (byte) 0xe0, (byte) 0xb7, (byte) 0x90, (byte) 0xa8, (byte) 0x4e,
+ (byte) 0x76, (byte) 0xfe, (byte) 0x89, (byte) 0x82, (byte) 0x7f, (byte) 0x7a, (byte) 0xc5, (byte) 0x3c,
+ (byte) 0x4e, (byte) 0x0c, (byte) 0x20, (byte) 0x55, (byte) 0x30, (byte) 0x95, (byte) 0x42, (byte) 0x85,
+ (byte) 0xe1, (byte) 0x40, (byte) 0x7d, (byte) 0x27, (byte) 0x8f, (byte) 0x07, (byte) 0x0d, (byte) 0xe8,
+ (byte) 0xdc, (byte) 0x99, (byte) 0xef, (byte) 0xb3, (byte) 0x07, (byte) 0x94, (byte) 0x34, (byte) 0xd6,
+ (byte) 0x7c, (byte) 0xff, (byte) 0x9c, (byte) 0xbe, (byte) 0x69, (byte) 0xd3, (byte) 0xeb, (byte) 0x44,
+ (byte) 0x37, (byte) 0x50, (byte) 0xef, (byte) 0x49, (byte) 0xf8, (byte) 0xe2, (byte) 0x5b, (byte) 0xd8,
+ (byte) 0xd1, (byte) 0x10, (byte) 0x84, (byte) 0x97, (byte) 0xea, (byte) 0xe3, (byte) 0xa5, (byte) 0x1c,
+ (byte) 0xc0, (byte) 0x4e, (byte) 0x69, (byte) 0xca, (byte) 0x70, (byte) 0x3d, (byte) 0x78, (byte) 0xb9,
+ (byte) 0x16, (byte) 0xe5, (byte) 0xfe, (byte) 0x61, (byte) 0x5d, (byte) 0x8a, (byte) 0x5a, (byte) 0xb3,
+ (byte) 0x2c, (byte) 0x61, (byte) 0xb6, (byte) 0x01, (byte) 0x3b, (byte) 0xd0, (byte) 0x01, (byte) 0x7c,
+ (byte) 0x32, (byte) 0x8d, (byte) 0xe1, (byte) 0xf3, (byte) 0x69, (byte) 0x0e, (byte) 0x8b, (byte) 0x58,
+ (byte) 0xc6, (byte) 0xcf, (byte) 0x00, (byte) 0x94, (byte) 0xf8, (byte) 0x49, (byte) 0x2a, (byte) 0x4b,
+ (byte) 0xea, (byte) 0xda, (byte) 0x00, (byte) 0xff, (byte) 0x4b, (byte) 0xd0, (byte) 0xbe, (byte) 0x40,
+ (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_Q = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xbf, (byte) 0xee, (byte) 0xaa, (byte) 0x0f, (byte) 0x12, (byte) 0x34, (byte) 0x50,
+ (byte) 0x72, (byte) 0xf8, (byte) 0x60, (byte) 0x13, (byte) 0xd8, (byte) 0xf1, (byte) 0x41, (byte) 0x01,
+ (byte) 0x10, (byte) 0xa5, (byte) 0x2f, (byte) 0x57, (byte) 0x5f,
+ });
+
+ private static final BigInteger DSA_G = new BigInteger(new byte[] {
+ (byte) 0x77, (byte) 0xd4, (byte) 0x7a, (byte) 0x12, (byte) 0xcc, (byte) 0x81, (byte) 0x7e, (byte) 0x7e,
+ (byte) 0xeb, (byte) 0x3a, (byte) 0xfb, (byte) 0xe6, (byte) 0x86, (byte) 0x6d, (byte) 0x5a, (byte) 0x10,
+ (byte) 0x1d, (byte) 0xad, (byte) 0xa9, (byte) 0x4f, (byte) 0xb9, (byte) 0x03, (byte) 0x5d, (byte) 0x21,
+ (byte) 0x1a, (byte) 0xe4, (byte) 0x30, (byte) 0x95, (byte) 0x75, (byte) 0x8e, (byte) 0xcd, (byte) 0x5e,
+ (byte) 0xd1, (byte) 0xbd, (byte) 0x0a, (byte) 0x45, (byte) 0xee, (byte) 0xe7, (byte) 0xf7, (byte) 0x6b,
+ (byte) 0x65, (byte) 0x02, (byte) 0x60, (byte) 0xd0, (byte) 0x2e, (byte) 0xaf, (byte) 0x3d, (byte) 0xbc,
+ (byte) 0x07, (byte) 0xdd, (byte) 0x2b, (byte) 0x8e, (byte) 0x33, (byte) 0xc0, (byte) 0x93, (byte) 0x80,
+ (byte) 0xd9, (byte) 0x2b, (byte) 0xa7, (byte) 0x71, (byte) 0x57, (byte) 0x76, (byte) 0xbc, (byte) 0x8e,
+ (byte) 0xb9, (byte) 0xe0, (byte) 0xd7, (byte) 0xf4, (byte) 0x23, (byte) 0x8d, (byte) 0x41, (byte) 0x1a,
+ (byte) 0x97, (byte) 0x4f, (byte) 0x2c, (byte) 0x1b, (byte) 0xd5, (byte) 0x4b, (byte) 0x66, (byte) 0xe8,
+ (byte) 0xfa, (byte) 0xd2, (byte) 0x50, (byte) 0x0d, (byte) 0x17, (byte) 0xab, (byte) 0x34, (byte) 0x31,
+ (byte) 0x3d, (byte) 0xa4, (byte) 0x88, (byte) 0xd8, (byte) 0x8e, (byte) 0xa8, (byte) 0xa7, (byte) 0x6e,
+ (byte) 0x17, (byte) 0x03, (byte) 0xb7, (byte) 0x0f, (byte) 0x68, (byte) 0x7c, (byte) 0x64, (byte) 0x7b,
+ (byte) 0x92, (byte) 0xb8, (byte) 0x63, (byte) 0xe4, (byte) 0x9a, (byte) 0x67, (byte) 0x18, (byte) 0x81,
+ (byte) 0x27, (byte) 0xd4, (byte) 0x0b, (byte) 0x13, (byte) 0x48, (byte) 0xd3, (byte) 0x7d, (byte) 0x4e,
+ (byte) 0xf6, (byte) 0xa8, (byte) 0x8f, (byte) 0x56, (byte) 0x17, (byte) 0x2d, (byte) 0x08, (byte) 0x51,
+ });
+
+ public void testDSAGeneratorWithParams() throws Exception {
+ final DSAParameterSpec dsaSpec = new DSAParameterSpec(DSA_P, DSA_Q, DSA_G);
+
+ boolean failure = false;
+
+ final Provider[] providers = Security.getProviders();
+ for (final Provider p : providers) {
+ Service s = p.getService("KeyPairGenerator", "DSA");
+ if (s == null) {
+ continue;
+ }
+
+ final KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", p);
+ kpg.initialize(dsaSpec);
+ KeyPair pair = kpg.generateKeyPair();
+ DSAPrivateKey privKey = (DSAPrivateKey) pair.getPrivate();
+ DSAPublicKey pubKey = (DSAPublicKey) pair.getPublic();
+
+ DSAParams actualParams = privKey.getParams();
+ assertNotNull("DSA params should not be null", actualParams);
+
+ assertEquals("DSA P should be the same as supplied with provider " + p.getName(),
+ DSA_P, actualParams.getP());
+ assertEquals("DSA Q should be the same as supplied with provider " + p.getName(),
+ DSA_Q, actualParams.getQ());
+ assertEquals("DSA G should be the same as supplied with provider " + p.getName(),
+ DSA_G, actualParams.getG());
+
+ actualParams = pubKey.getParams();
+ assertNotNull("DSA params should not be null", actualParams);
+
+ assertEquals("DSA P should be the same as supplied with provider " + p.getName(),
+ DSA_P, actualParams.getP());
+ assertEquals("DSA Q should be the same as supplied with provider " + p.getName(),
+ DSA_Q, actualParams.getQ());
+ assertEquals("DSA G should be the same as supplied with provider " + p.getName(),
+ DSA_G, actualParams.getG());
+ }
}
}
diff --git a/luni/src/test/java/libcore/java/security/KeyStoreTest.java b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
index 0a4d966..14d0987 100644
--- a/luni/src/test/java/libcore/java/security/KeyStoreTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
@@ -68,6 +68,10 @@
private static final String ALIAS_ALT_CASE_CERTIFICATE = "cErTiFiCaTe";
private static final String ALIAS_ALT_CASE_SECRET = "sEcRet";
+ private static final String ALIAS_UNICODE_PRIVATE = "\u6400\u7902\u3101\u8c02\u5002\u8702\udd01";
+ private static final String ALIAS_UNICODE_CERTIFICATE = "\u5402\udd01\u7902\u8702\u3101\u5f02\u3101\u5402\u5002\u8702\udd01";
+ private static final String ALIAS_UNICODE_SECRET = "\ue224\ud424\ud224\ue124\ud424\ue324";
+
private static final String ALIAS_NO_PASSWORD_PRIVATE = "private-no-password";
private static final String ALIAS_NO_PASSWORD_SECRET = "secret-no-password";
@@ -1208,7 +1212,7 @@
assertTrue(keyStore.aliases().hasMoreElements());
} else {
assertEquals(Collections.EMPTY_SET,
- new HashSet(Collections.list(keyStore.aliases())));
+ new HashSet(Collections.list(keyStore.aliases())));
}
}
@@ -1396,14 +1400,14 @@
assertFalse(keyStore.isCertificateEntry(ALIAS_PRIVATE));
assertFalse(keyStore.isCertificateEntry(ALIAS_SECRET));
assertEquals(isCertificateEnabled(keyStore) && !isReadOnly(keyStore),
- keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
+ keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
assertFalse(keyStore.isCertificateEntry(ALIAS_ALT_CASE_PRIVATE));
assertFalse(keyStore.isCertificateEntry(ALIAS_ALT_CASE_SECRET));
assertEquals(!isCaseSensitive(keyStore)
- && isCertificateEnabled(keyStore)
- && !isReadOnly(keyStore),
- keyStore.isCertificateEntry(ALIAS_ALT_CASE_CERTIFICATE));
+ && isCertificateEnabled(keyStore)
+ && !isReadOnly(keyStore),
+ keyStore.isCertificateEntry(ALIAS_ALT_CASE_CERTIFICATE));
}
}
@@ -1832,6 +1836,20 @@
} catch (KeyStoreException expected) {
}
}
+ keyStore.setEntry(ALIAS_UNICODE_PRIVATE, getPrivateKey(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_UNICODE_PRIVATE));
+ if (isSecretKeyEnabled(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_UNICODE_SECRET, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_UNICODE_SECRET, new SecretKeyEntry(getSecretKey()), PARAM_KEY);
+ assertSecretKey(keyStore.getKey(ALIAS_UNICODE_SECRET, PASSWORD_KEY));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_UNICODE_SECRET, getSecretKey(), PASSWORD_KEY, null);
+ fail();
+ } catch (KeyStoreException expected) {
+ }
+ }
}
for (KeyStore keyStore : keyStores()) {
@@ -1868,6 +1886,11 @@
null);
assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_UNICODE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_UNICODE_CERTIFICATE));
}
} else {
assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
@@ -1895,6 +1918,11 @@
null);
assertCertificate2(keyStore.getCertificate(ALIAS_CERTIFICATE));
assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_UNICODE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_UNICODE_CERTIFICATE));
}
}
}
@@ -2183,4 +2211,24 @@
}
}
}
+
+ // http://b/857840: want JKS key store
+ public void testDefaultKeystore() {
+ String type = KeyStore.getDefaultType();
+ assertEquals("Default keystore type must be Bouncy Castle", "BKS", type);
+
+ try {
+ KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
+ assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ try {
+ KeyStore store = KeyStore.getInstance("BKS");
+ assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 75aada1..7364c93 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -16,14 +16,24 @@
package libcore.java.security;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -159,4 +169,860 @@
sig.update(CONTENT);
assertTrue(sig.verify(SIGNATURE));
}
+
+ /*
+ * Test vectors generated with this private key:
+ *
+ * -----BEGIN RSA PRIVATE KEY-----
+ * MIIEpAIBAAKCAQEA4Ec+irjyKE/rnnQv+XSPoRjtmGM8kvUq63ouvg075gMpvnZq
+ * 0Q62pRXQ0s/ZvqeTDwwwZTeJn3lYzT6FsB+IGFJNMSWEqUslHjYltUFB7b/uGYgI
+ * 4buX/Hy0m56qr2jpyY19DtxTu8D6ADQ1bWMF+7zDxwAUBThqu8hzyw8+90JfPTPf
+ * ezFa4DbSoLZq/UdQOxab8247UWJRW3Ff2oPeryxYrrmr+zCXw8yd2dvl7ylsF2E5
+ * Ao6KZx5jBW1F9AGI0sQTNJCEXeUsJTTpxrJHjAe9rpKII7YtBmx3cPn2Pz26JH9T
+ * CER0e+eqqF2FO4vSRKzsPePImrRkU6tNJMOsaQIDAQABAoIBADd4R3al8XaY9ayW
+ * DfuDobZ1ZOZIvQWXz4q4CHGG8macJ6nsvdSA8Bl6gNBzCebGqW+SUzHlf4tKxvTU
+ * XtpFojJpwJ/EKMB6Tm7fc4oV3sl/q9Lyu0ehTyDqcvz+TDbgGtp3vRN82NTaELsW
+ * LpSkZilx8XX5hfoYjwVsuX7igW9Dq503R2Ekhs2owWGWwwgYqZXshdOEZ3kSZ7O/
+ * IfJzcQppJYYldoQcW2cSwS1L0govMpmtt8E12l6VFavadufK8qO+gFUdBzt4vxFi
+ * xIrSt/R0OgI47k0lL31efmUzzK5kzLOTYAdaL9HgNOw65c6cQIzL8OJeQRQCFoez
+ * 3UdUroECgYEA9UGIS8Nzeyki1BGe9F4t7izUy7dfRVBaFXqlAJ+Zxzot8HJKxGAk
+ * MGMy6omBd2NFRl3G3x4KbxQK/ztzluaomUrF2qloc0cv43dJ0U6z4HXmKdvrNYMz
+ * im82SdCiZUp6Qv2atr+krE1IHTkLsimwZL3DEcwb4bYxidp8QM3s8rECgYEA6hp0
+ * LduIHO23KIyH442GjdekCdFaQ/RF1Td6C1cx3b/KLa8oqOE81cCvzsM0fXSjniNa
+ * PNljPydN4rlPkt9DgzkR2enxz1jyfeLgj/RZZMcg0+whOdx8r8kSlTzeyy81Wi4s
+ * NaUPrXVMs7IxZkJLo7bjESoriYw4xcFe2yOGkzkCgYBRgo8exv2ZYCmQG68dfjN7
+ * pfCvJ+mE6tiVrOYr199O5FoiQInyzBUa880XP84EdLywTzhqLNzA4ANrokGfVFeS
+ * YtRxAL6TGYSj76Bb7PFBV03AebOpXEqD5sQ/MhTW3zLVEt4ZgIXlMeYWuD/X3Z0f
+ * TiYHwzM9B8VdEH0dOJNYcQKBgQDbT7UPUN6O21P/NMgJMYigUShn2izKBIl3WeWH
+ * wkQBDa+GZNWegIPRbBZHiTAfZ6nweAYNg0oq29NnV1toqKhCwrAqibPzH8zsiiL+
+ * OVeVxcbHQitOXXSh6ajzDndZufwtY5wfFWc+hOk6XvFQb0MVODw41Fy9GxQEj0ch
+ * 3IIyYQKBgQDYEUWTr0FfthLb8ZI3ENVNB0hiBadqO0MZSWjA3/HxHvD2GkozfV/T
+ * dBu8lkDkR7i2tsR8OsEgQ1fTsMVbqShr2nP2KSlvX6kUbYl2NX08dR51FIaWpAt0
+ * aFyCzjCQLWOdck/yTV4ulAfuNO3tLjtN9lqpvP623yjQe6aQPxZXaA==
+ * -----END RSA PRIVATE KEY-----
+ *
+ */
+
+ private static final BigInteger RSA_2048_modulus = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xe0, (byte) 0x47, (byte) 0x3e, (byte) 0x8a, (byte) 0xb8, (byte) 0xf2, (byte) 0x28,
+ (byte) 0x4f, (byte) 0xeb, (byte) 0x9e, (byte) 0x74, (byte) 0x2f, (byte) 0xf9, (byte) 0x74, (byte) 0x8f,
+ (byte) 0xa1, (byte) 0x18, (byte) 0xed, (byte) 0x98, (byte) 0x63, (byte) 0x3c, (byte) 0x92, (byte) 0xf5,
+ (byte) 0x2a, (byte) 0xeb, (byte) 0x7a, (byte) 0x2e, (byte) 0xbe, (byte) 0x0d, (byte) 0x3b, (byte) 0xe6,
+ (byte) 0x03, (byte) 0x29, (byte) 0xbe, (byte) 0x76, (byte) 0x6a, (byte) 0xd1, (byte) 0x0e, (byte) 0xb6,
+ (byte) 0xa5, (byte) 0x15, (byte) 0xd0, (byte) 0xd2, (byte) 0xcf, (byte) 0xd9, (byte) 0xbe, (byte) 0xa7,
+ (byte) 0x93, (byte) 0x0f, (byte) 0x0c, (byte) 0x30, (byte) 0x65, (byte) 0x37, (byte) 0x89, (byte) 0x9f,
+ (byte) 0x79, (byte) 0x58, (byte) 0xcd, (byte) 0x3e, (byte) 0x85, (byte) 0xb0, (byte) 0x1f, (byte) 0x88,
+ (byte) 0x18, (byte) 0x52, (byte) 0x4d, (byte) 0x31, (byte) 0x25, (byte) 0x84, (byte) 0xa9, (byte) 0x4b,
+ (byte) 0x25, (byte) 0x1e, (byte) 0x36, (byte) 0x25, (byte) 0xb5, (byte) 0x41, (byte) 0x41, (byte) 0xed,
+ (byte) 0xbf, (byte) 0xee, (byte) 0x19, (byte) 0x88, (byte) 0x08, (byte) 0xe1, (byte) 0xbb, (byte) 0x97,
+ (byte) 0xfc, (byte) 0x7c, (byte) 0xb4, (byte) 0x9b, (byte) 0x9e, (byte) 0xaa, (byte) 0xaf, (byte) 0x68,
+ (byte) 0xe9, (byte) 0xc9, (byte) 0x8d, (byte) 0x7d, (byte) 0x0e, (byte) 0xdc, (byte) 0x53, (byte) 0xbb,
+ (byte) 0xc0, (byte) 0xfa, (byte) 0x00, (byte) 0x34, (byte) 0x35, (byte) 0x6d, (byte) 0x63, (byte) 0x05,
+ (byte) 0xfb, (byte) 0xbc, (byte) 0xc3, (byte) 0xc7, (byte) 0x00, (byte) 0x14, (byte) 0x05, (byte) 0x38,
+ (byte) 0x6a, (byte) 0xbb, (byte) 0xc8, (byte) 0x73, (byte) 0xcb, (byte) 0x0f, (byte) 0x3e, (byte) 0xf7,
+ (byte) 0x42, (byte) 0x5f, (byte) 0x3d, (byte) 0x33, (byte) 0xdf, (byte) 0x7b, (byte) 0x31, (byte) 0x5a,
+ (byte) 0xe0, (byte) 0x36, (byte) 0xd2, (byte) 0xa0, (byte) 0xb6, (byte) 0x6a, (byte) 0xfd, (byte) 0x47,
+ (byte) 0x50, (byte) 0x3b, (byte) 0x16, (byte) 0x9b, (byte) 0xf3, (byte) 0x6e, (byte) 0x3b, (byte) 0x51,
+ (byte) 0x62, (byte) 0x51, (byte) 0x5b, (byte) 0x71, (byte) 0x5f, (byte) 0xda, (byte) 0x83, (byte) 0xde,
+ (byte) 0xaf, (byte) 0x2c, (byte) 0x58, (byte) 0xae, (byte) 0xb9, (byte) 0xab, (byte) 0xfb, (byte) 0x30,
+ (byte) 0x97, (byte) 0xc3, (byte) 0xcc, (byte) 0x9d, (byte) 0xd9, (byte) 0xdb, (byte) 0xe5, (byte) 0xef,
+ (byte) 0x29, (byte) 0x6c, (byte) 0x17, (byte) 0x61, (byte) 0x39, (byte) 0x02, (byte) 0x8e, (byte) 0x8a,
+ (byte) 0x67, (byte) 0x1e, (byte) 0x63, (byte) 0x05, (byte) 0x6d, (byte) 0x45, (byte) 0xf4, (byte) 0x01,
+ (byte) 0x88, (byte) 0xd2, (byte) 0xc4, (byte) 0x13, (byte) 0x34, (byte) 0x90, (byte) 0x84, (byte) 0x5d,
+ (byte) 0xe5, (byte) 0x2c, (byte) 0x25, (byte) 0x34, (byte) 0xe9, (byte) 0xc6, (byte) 0xb2, (byte) 0x47,
+ (byte) 0x8c, (byte) 0x07, (byte) 0xbd, (byte) 0xae, (byte) 0x92, (byte) 0x88, (byte) 0x23, (byte) 0xb6,
+ (byte) 0x2d, (byte) 0x06, (byte) 0x6c, (byte) 0x77, (byte) 0x70, (byte) 0xf9, (byte) 0xf6, (byte) 0x3f,
+ (byte) 0x3d, (byte) 0xba, (byte) 0x24, (byte) 0x7f, (byte) 0x53, (byte) 0x08, (byte) 0x44, (byte) 0x74,
+ (byte) 0x7b, (byte) 0xe7, (byte) 0xaa, (byte) 0xa8, (byte) 0x5d, (byte) 0x85, (byte) 0x3b, (byte) 0x8b,
+ (byte) 0xd2, (byte) 0x44, (byte) 0xac, (byte) 0xec, (byte) 0x3d, (byte) 0xe3, (byte) 0xc8, (byte) 0x9a,
+ (byte) 0xb4, (byte) 0x64, (byte) 0x53, (byte) 0xab, (byte) 0x4d, (byte) 0x24, (byte) 0xc3, (byte) 0xac,
+ (byte) 0x69,
+ });
+
+ private static final BigInteger RSA_2048_privateExponent = new BigInteger(new byte[] {
+ (byte) 0x37, (byte) 0x78, (byte) 0x47, (byte) 0x76, (byte) 0xa5, (byte) 0xf1, (byte) 0x76, (byte) 0x98,
+ (byte) 0xf5, (byte) 0xac, (byte) 0x96, (byte) 0x0d, (byte) 0xfb, (byte) 0x83, (byte) 0xa1, (byte) 0xb6,
+ (byte) 0x75, (byte) 0x64, (byte) 0xe6, (byte) 0x48, (byte) 0xbd, (byte) 0x05, (byte) 0x97, (byte) 0xcf,
+ (byte) 0x8a, (byte) 0xb8, (byte) 0x08, (byte) 0x71, (byte) 0x86, (byte) 0xf2, (byte) 0x66, (byte) 0x9c,
+ (byte) 0x27, (byte) 0xa9, (byte) 0xec, (byte) 0xbd, (byte) 0xd4, (byte) 0x80, (byte) 0xf0, (byte) 0x19,
+ (byte) 0x7a, (byte) 0x80, (byte) 0xd0, (byte) 0x73, (byte) 0x09, (byte) 0xe6, (byte) 0xc6, (byte) 0xa9,
+ (byte) 0x6f, (byte) 0x92, (byte) 0x53, (byte) 0x31, (byte) 0xe5, (byte) 0x7f, (byte) 0x8b, (byte) 0x4a,
+ (byte) 0xc6, (byte) 0xf4, (byte) 0xd4, (byte) 0x5e, (byte) 0xda, (byte) 0x45, (byte) 0xa2, (byte) 0x32,
+ (byte) 0x69, (byte) 0xc0, (byte) 0x9f, (byte) 0xc4, (byte) 0x28, (byte) 0xc0, (byte) 0x7a, (byte) 0x4e,
+ (byte) 0x6e, (byte) 0xdf, (byte) 0x73, (byte) 0x8a, (byte) 0x15, (byte) 0xde, (byte) 0xc9, (byte) 0x7f,
+ (byte) 0xab, (byte) 0xd2, (byte) 0xf2, (byte) 0xbb, (byte) 0x47, (byte) 0xa1, (byte) 0x4f, (byte) 0x20,
+ (byte) 0xea, (byte) 0x72, (byte) 0xfc, (byte) 0xfe, (byte) 0x4c, (byte) 0x36, (byte) 0xe0, (byte) 0x1a,
+ (byte) 0xda, (byte) 0x77, (byte) 0xbd, (byte) 0x13, (byte) 0x7c, (byte) 0xd8, (byte) 0xd4, (byte) 0xda,
+ (byte) 0x10, (byte) 0xbb, (byte) 0x16, (byte) 0x2e, (byte) 0x94, (byte) 0xa4, (byte) 0x66, (byte) 0x29,
+ (byte) 0x71, (byte) 0xf1, (byte) 0x75, (byte) 0xf9, (byte) 0x85, (byte) 0xfa, (byte) 0x18, (byte) 0x8f,
+ (byte) 0x05, (byte) 0x6c, (byte) 0xb9, (byte) 0x7e, (byte) 0xe2, (byte) 0x81, (byte) 0x6f, (byte) 0x43,
+ (byte) 0xab, (byte) 0x9d, (byte) 0x37, (byte) 0x47, (byte) 0x61, (byte) 0x24, (byte) 0x86, (byte) 0xcd,
+ (byte) 0xa8, (byte) 0xc1, (byte) 0x61, (byte) 0x96, (byte) 0xc3, (byte) 0x08, (byte) 0x18, (byte) 0xa9,
+ (byte) 0x95, (byte) 0xec, (byte) 0x85, (byte) 0xd3, (byte) 0x84, (byte) 0x67, (byte) 0x79, (byte) 0x12,
+ (byte) 0x67, (byte) 0xb3, (byte) 0xbf, (byte) 0x21, (byte) 0xf2, (byte) 0x73, (byte) 0x71, (byte) 0x0a,
+ (byte) 0x69, (byte) 0x25, (byte) 0x86, (byte) 0x25, (byte) 0x76, (byte) 0x84, (byte) 0x1c, (byte) 0x5b,
+ (byte) 0x67, (byte) 0x12, (byte) 0xc1, (byte) 0x2d, (byte) 0x4b, (byte) 0xd2, (byte) 0x0a, (byte) 0x2f,
+ (byte) 0x32, (byte) 0x99, (byte) 0xad, (byte) 0xb7, (byte) 0xc1, (byte) 0x35, (byte) 0xda, (byte) 0x5e,
+ (byte) 0x95, (byte) 0x15, (byte) 0xab, (byte) 0xda, (byte) 0x76, (byte) 0xe7, (byte) 0xca, (byte) 0xf2,
+ (byte) 0xa3, (byte) 0xbe, (byte) 0x80, (byte) 0x55, (byte) 0x1d, (byte) 0x07, (byte) 0x3b, (byte) 0x78,
+ (byte) 0xbf, (byte) 0x11, (byte) 0x62, (byte) 0xc4, (byte) 0x8a, (byte) 0xd2, (byte) 0xb7, (byte) 0xf4,
+ (byte) 0x74, (byte) 0x3a, (byte) 0x02, (byte) 0x38, (byte) 0xee, (byte) 0x4d, (byte) 0x25, (byte) 0x2f,
+ (byte) 0x7d, (byte) 0x5e, (byte) 0x7e, (byte) 0x65, (byte) 0x33, (byte) 0xcc, (byte) 0xae, (byte) 0x64,
+ (byte) 0xcc, (byte) 0xb3, (byte) 0x93, (byte) 0x60, (byte) 0x07, (byte) 0x5a, (byte) 0x2f, (byte) 0xd1,
+ (byte) 0xe0, (byte) 0x34, (byte) 0xec, (byte) 0x3a, (byte) 0xe5, (byte) 0xce, (byte) 0x9c, (byte) 0x40,
+ (byte) 0x8c, (byte) 0xcb, (byte) 0xf0, (byte) 0xe2, (byte) 0x5e, (byte) 0x41, (byte) 0x14, (byte) 0x02,
+ (byte) 0x16, (byte) 0x87, (byte) 0xb3, (byte) 0xdd, (byte) 0x47, (byte) 0x54, (byte) 0xae, (byte) 0x81,
+ });
+
+ private static final BigInteger RSA_2048_publicExponent = new BigInteger(new byte[] {
+ (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ });
+
+ private static final BigInteger RSA_2048_primeP = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xf5, (byte) 0x41, (byte) 0x88, (byte) 0x4b, (byte) 0xc3, (byte) 0x73, (byte) 0x7b,
+ (byte) 0x29, (byte) 0x22, (byte) 0xd4, (byte) 0x11, (byte) 0x9e, (byte) 0xf4, (byte) 0x5e, (byte) 0x2d,
+ (byte) 0xee, (byte) 0x2c, (byte) 0xd4, (byte) 0xcb, (byte) 0xb7, (byte) 0x5f, (byte) 0x45, (byte) 0x50,
+ (byte) 0x5a, (byte) 0x15, (byte) 0x7a, (byte) 0xa5, (byte) 0x00, (byte) 0x9f, (byte) 0x99, (byte) 0xc7,
+ (byte) 0x3a, (byte) 0x2d, (byte) 0xf0, (byte) 0x72, (byte) 0x4a, (byte) 0xc4, (byte) 0x60, (byte) 0x24,
+ (byte) 0x30, (byte) 0x63, (byte) 0x32, (byte) 0xea, (byte) 0x89, (byte) 0x81, (byte) 0x77, (byte) 0x63,
+ (byte) 0x45, (byte) 0x46, (byte) 0x5d, (byte) 0xc6, (byte) 0xdf, (byte) 0x1e, (byte) 0x0a, (byte) 0x6f,
+ (byte) 0x14, (byte) 0x0a, (byte) 0xff, (byte) 0x3b, (byte) 0x73, (byte) 0x96, (byte) 0xe6, (byte) 0xa8,
+ (byte) 0x99, (byte) 0x4a, (byte) 0xc5, (byte) 0xda, (byte) 0xa9, (byte) 0x68, (byte) 0x73, (byte) 0x47,
+ (byte) 0x2f, (byte) 0xe3, (byte) 0x77, (byte) 0x49, (byte) 0xd1, (byte) 0x4e, (byte) 0xb3, (byte) 0xe0,
+ (byte) 0x75, (byte) 0xe6, (byte) 0x29, (byte) 0xdb, (byte) 0xeb, (byte) 0x35, (byte) 0x83, (byte) 0x33,
+ (byte) 0x8a, (byte) 0x6f, (byte) 0x36, (byte) 0x49, (byte) 0xd0, (byte) 0xa2, (byte) 0x65, (byte) 0x4a,
+ (byte) 0x7a, (byte) 0x42, (byte) 0xfd, (byte) 0x9a, (byte) 0xb6, (byte) 0xbf, (byte) 0xa4, (byte) 0xac,
+ (byte) 0x4d, (byte) 0x48, (byte) 0x1d, (byte) 0x39, (byte) 0x0b, (byte) 0xb2, (byte) 0x29, (byte) 0xb0,
+ (byte) 0x64, (byte) 0xbd, (byte) 0xc3, (byte) 0x11, (byte) 0xcc, (byte) 0x1b, (byte) 0xe1, (byte) 0xb6,
+ (byte) 0x31, (byte) 0x89, (byte) 0xda, (byte) 0x7c, (byte) 0x40, (byte) 0xcd, (byte) 0xec, (byte) 0xf2,
+ (byte) 0xb1,
+ });
+
+ private static final BigInteger RSA_2048_primeQ = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xea, (byte) 0x1a, (byte) 0x74, (byte) 0x2d, (byte) 0xdb, (byte) 0x88, (byte) 0x1c,
+ (byte) 0xed, (byte) 0xb7, (byte) 0x28, (byte) 0x8c, (byte) 0x87, (byte) 0xe3, (byte) 0x8d, (byte) 0x86,
+ (byte) 0x8d, (byte) 0xd7, (byte) 0xa4, (byte) 0x09, (byte) 0xd1, (byte) 0x5a, (byte) 0x43, (byte) 0xf4,
+ (byte) 0x45, (byte) 0xd5, (byte) 0x37, (byte) 0x7a, (byte) 0x0b, (byte) 0x57, (byte) 0x31, (byte) 0xdd,
+ (byte) 0xbf, (byte) 0xca, (byte) 0x2d, (byte) 0xaf, (byte) 0x28, (byte) 0xa8, (byte) 0xe1, (byte) 0x3c,
+ (byte) 0xd5, (byte) 0xc0, (byte) 0xaf, (byte) 0xce, (byte) 0xc3, (byte) 0x34, (byte) 0x7d, (byte) 0x74,
+ (byte) 0xa3, (byte) 0x9e, (byte) 0x23, (byte) 0x5a, (byte) 0x3c, (byte) 0xd9, (byte) 0x63, (byte) 0x3f,
+ (byte) 0x27, (byte) 0x4d, (byte) 0xe2, (byte) 0xb9, (byte) 0x4f, (byte) 0x92, (byte) 0xdf, (byte) 0x43,
+ (byte) 0x83, (byte) 0x39, (byte) 0x11, (byte) 0xd9, (byte) 0xe9, (byte) 0xf1, (byte) 0xcf, (byte) 0x58,
+ (byte) 0xf2, (byte) 0x7d, (byte) 0xe2, (byte) 0xe0, (byte) 0x8f, (byte) 0xf4, (byte) 0x59, (byte) 0x64,
+ (byte) 0xc7, (byte) 0x20, (byte) 0xd3, (byte) 0xec, (byte) 0x21, (byte) 0x39, (byte) 0xdc, (byte) 0x7c,
+ (byte) 0xaf, (byte) 0xc9, (byte) 0x12, (byte) 0x95, (byte) 0x3c, (byte) 0xde, (byte) 0xcb, (byte) 0x2f,
+ (byte) 0x35, (byte) 0x5a, (byte) 0x2e, (byte) 0x2c, (byte) 0x35, (byte) 0xa5, (byte) 0x0f, (byte) 0xad,
+ (byte) 0x75, (byte) 0x4c, (byte) 0xb3, (byte) 0xb2, (byte) 0x31, (byte) 0x66, (byte) 0x42, (byte) 0x4b,
+ (byte) 0xa3, (byte) 0xb6, (byte) 0xe3, (byte) 0x11, (byte) 0x2a, (byte) 0x2b, (byte) 0x89, (byte) 0x8c,
+ (byte) 0x38, (byte) 0xc5, (byte) 0xc1, (byte) 0x5e, (byte) 0xdb, (byte) 0x23, (byte) 0x86, (byte) 0x93,
+ (byte) 0x39,
+ });
+
+ private static final byte[] Vector1Data = new byte[] {
+ (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x2e,
+ (byte) 0x0a,
+ };
+
+ private static final byte[] SHA1withRSA_Vector1Signature = {
+ (byte) 0x6d, (byte) 0x5b, (byte) 0xff, (byte) 0x68, (byte) 0xda, (byte) 0x18, (byte) 0x98, (byte) 0x72,
+ (byte) 0x5c, (byte) 0x1f, (byte) 0x46, (byte) 0x51, (byte) 0x77, (byte) 0x15, (byte) 0x11, (byte) 0xcb,
+ (byte) 0xe0, (byte) 0xb9, (byte) 0x3b, (byte) 0x7d, (byte) 0xf5, (byte) 0x96, (byte) 0x98, (byte) 0x24,
+ (byte) 0x85, (byte) 0x9d, (byte) 0x3e, (byte) 0xed, (byte) 0x9b, (byte) 0xb2, (byte) 0x8a, (byte) 0x91,
+ (byte) 0xfb, (byte) 0xf6, (byte) 0x85, (byte) 0x64, (byte) 0x74, (byte) 0x18, (byte) 0xb5, (byte) 0x1c,
+ (byte) 0xb3, (byte) 0x8d, (byte) 0x99, (byte) 0x0d, (byte) 0xdf, (byte) 0xaa, (byte) 0xa6, (byte) 0xa1,
+ (byte) 0xc3, (byte) 0xb6, (byte) 0x25, (byte) 0xb3, (byte) 0x06, (byte) 0xe0, (byte) 0xef, (byte) 0x28,
+ (byte) 0xb0, (byte) 0x4d, (byte) 0x50, (byte) 0xc7, (byte) 0x75, (byte) 0x39, (byte) 0xb9, (byte) 0x2c,
+ (byte) 0x47, (byte) 0xb5, (byte) 0xe2, (byte) 0x96, (byte) 0xf8, (byte) 0xf6, (byte) 0xcb, (byte) 0xa0,
+ (byte) 0x58, (byte) 0xc9, (byte) 0x3e, (byte) 0xd5, (byte) 0xfc, (byte) 0x26, (byte) 0xd9, (byte) 0x55,
+ (byte) 0x73, (byte) 0x39, (byte) 0x75, (byte) 0xb3, (byte) 0xb0, (byte) 0x0a, (byte) 0x5f, (byte) 0x5e,
+ (byte) 0x3b, (byte) 0x4a, (byte) 0x2e, (byte) 0xb1, (byte) 0x0e, (byte) 0x7d, (byte) 0xe5, (byte) 0xcc,
+ (byte) 0x04, (byte) 0x2c, (byte) 0xd1, (byte) 0x0a, (byte) 0x32, (byte) 0xaa, (byte) 0xd9, (byte) 0x8d,
+ (byte) 0x1f, (byte) 0xcb, (byte) 0xe3, (byte) 0x7f, (byte) 0x63, (byte) 0x12, (byte) 0xb1, (byte) 0x98,
+ (byte) 0x46, (byte) 0x46, (byte) 0x07, (byte) 0xd9, (byte) 0x49, (byte) 0xd2, (byte) 0xbf, (byte) 0xb5,
+ (byte) 0xbc, (byte) 0xbb, (byte) 0xfd, (byte) 0x1c, (byte) 0xd7, (byte) 0x11, (byte) 0x94, (byte) 0xaa,
+ (byte) 0x5f, (byte) 0x7b, (byte) 0xb2, (byte) 0x0c, (byte) 0x5d, (byte) 0x94, (byte) 0x53, (byte) 0x5e,
+ (byte) 0x81, (byte) 0x5c, (byte) 0xbb, (byte) 0x1d, (byte) 0x4f, (byte) 0x30, (byte) 0xcd, (byte) 0xf8,
+ (byte) 0xd7, (byte) 0xa5, (byte) 0xfa, (byte) 0x5e, (byte) 0xe0, (byte) 0x19, (byte) 0x3f, (byte) 0xa4,
+ (byte) 0xaa, (byte) 0x56, (byte) 0x4e, (byte) 0xec, (byte) 0xeb, (byte) 0xee, (byte) 0xa2, (byte) 0x6c,
+ (byte) 0xc9, (byte) 0x4f, (byte) 0xc2, (byte) 0xcc, (byte) 0x2a, (byte) 0xbc, (byte) 0x5b, (byte) 0x09,
+ (byte) 0x10, (byte) 0x73, (byte) 0x61, (byte) 0x0c, (byte) 0x04, (byte) 0xb6, (byte) 0xb7, (byte) 0x2c,
+ (byte) 0x37, (byte) 0xd2, (byte) 0xca, (byte) 0x2d, (byte) 0x54, (byte) 0xf2, (byte) 0xf7, (byte) 0x77,
+ (byte) 0xe1, (byte) 0xba, (byte) 0x9f, (byte) 0x29, (byte) 0x07, (byte) 0xa2, (byte) 0x74, (byte) 0xc6,
+ (byte) 0xe9, (byte) 0x1e, (byte) 0xde, (byte) 0xd7, (byte) 0x9c, (byte) 0x4b, (byte) 0xb7, (byte) 0x66,
+ (byte) 0x52, (byte) 0xe8, (byte) 0xac, (byte) 0xf6, (byte) 0x76, (byte) 0xab, (byte) 0x16, (byte) 0x82,
+ (byte) 0x96, (byte) 0x87, (byte) 0x40, (byte) 0x0f, (byte) 0xad, (byte) 0x2d, (byte) 0x46, (byte) 0xa6,
+ (byte) 0x28, (byte) 0x04, (byte) 0x13, (byte) 0xc2, (byte) 0xce, (byte) 0x50, (byte) 0x56, (byte) 0x6d,
+ (byte) 0xbe, (byte) 0x0c, (byte) 0x91, (byte) 0xd0, (byte) 0x8e, (byte) 0x80, (byte) 0x9e, (byte) 0x91,
+ (byte) 0x8f, (byte) 0x62, (byte) 0xb3, (byte) 0x57, (byte) 0xd6, (byte) 0xae, (byte) 0x53, (byte) 0x91,
+ (byte) 0x83, (byte) 0xe9, (byte) 0x38, (byte) 0x77, (byte) 0x8f, (byte) 0x20, (byte) 0xdd, (byte) 0x13,
+ (byte) 0x7d, (byte) 0x15, (byte) 0x44, (byte) 0x7e, (byte) 0xb5, (byte) 0x00, (byte) 0xd6, (byte) 0x45,
+ };
+
+ private static final byte[] Vector2Data = new byte[] {
+ (byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, (byte) 0x20,
+ (byte) 0x61, (byte) 0x20, (byte) 0x73, (byte) 0x69, (byte) 0x67, (byte) 0x6e, (byte) 0x65, (byte) 0x64,
+ (byte) 0x20, (byte) 0x6d, (byte) 0x65, (byte) 0x73, (byte) 0x73, (byte) 0x61, (byte) 0x67, (byte) 0x65,
+ (byte) 0x20, (byte) 0x66, (byte) 0x72, (byte) 0x6f, (byte) 0x6d, (byte) 0x20, (byte) 0x4b, (byte) 0x65,
+ (byte) 0x6e, (byte) 0x6e, (byte) 0x79, (byte) 0x20, (byte) 0x52, (byte) 0x6f, (byte) 0x6f, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x0a,
+ };
+
+ private static final byte[] SHA1withRSA_Vector2Signature = new byte[] {
+ (byte) 0x2e, (byte) 0xa6, (byte) 0x33, (byte) 0xd1, (byte) 0x9d, (byte) 0xfc, (byte) 0x4e, (byte) 0x27,
+ (byte) 0xb3, (byte) 0xa8, (byte) 0x9a, (byte) 0xf2, (byte) 0x48, (byte) 0x62, (byte) 0x15, (byte) 0xa2,
+ (byte) 0xce, (byte) 0x5f, (byte) 0x2b, (byte) 0x0e, (byte) 0xc5, (byte) 0x26, (byte) 0xba, (byte) 0xd9,
+ (byte) 0x0f, (byte) 0x60, (byte) 0xeb, (byte) 0xf0, (byte) 0xd5, (byte) 0x5c, (byte) 0x6b, (byte) 0x23,
+ (byte) 0x11, (byte) 0x95, (byte) 0xa4, (byte) 0xbd, (byte) 0x11, (byte) 0x68, (byte) 0xe7, (byte) 0x3a,
+ (byte) 0x37, (byte) 0x3d, (byte) 0x79, (byte) 0xb8, (byte) 0x4f, (byte) 0xe9, (byte) 0xa1, (byte) 0x88,
+ (byte) 0xfb, (byte) 0xa9, (byte) 0x8b, (byte) 0x34, (byte) 0xa1, (byte) 0xe0, (byte) 0xca, (byte) 0x11,
+ (byte) 0xdd, (byte) 0xd0, (byte) 0x83, (byte) 0x7f, (byte) 0xc1, (byte) 0x0b, (byte) 0x16, (byte) 0x61,
+ (byte) 0xac, (byte) 0x09, (byte) 0xa2, (byte) 0xdd, (byte) 0x40, (byte) 0x5b, (byte) 0x8c, (byte) 0x7a,
+ (byte) 0xb2, (byte) 0xb4, (byte) 0x02, (byte) 0x7c, (byte) 0xd4, (byte) 0x9a, (byte) 0xe6, (byte) 0xa5,
+ (byte) 0x1a, (byte) 0x27, (byte) 0x77, (byte) 0x70, (byte) 0xe3, (byte) 0xe3, (byte) 0x71, (byte) 0xc7,
+ (byte) 0x59, (byte) 0xc7, (byte) 0x9f, (byte) 0xb8, (byte) 0xef, (byte) 0xe7, (byte) 0x15, (byte) 0x02,
+ (byte) 0x0d, (byte) 0x70, (byte) 0xdc, (byte) 0x2c, (byte) 0xe9, (byte) 0xf7, (byte) 0x63, (byte) 0x2a,
+ (byte) 0xb5, (byte) 0xee, (byte) 0x9f, (byte) 0x29, (byte) 0x56, (byte) 0x86, (byte) 0x99, (byte) 0xb3,
+ (byte) 0x0f, (byte) 0xe5, (byte) 0x1f, (byte) 0x76, (byte) 0x22, (byte) 0x3b, (byte) 0x7f, (byte) 0xa9,
+ (byte) 0x9e, (byte) 0xd4, (byte) 0xc4, (byte) 0x83, (byte) 0x5d, (byte) 0x57, (byte) 0xcc, (byte) 0x37,
+ (byte) 0xcb, (byte) 0x9a, (byte) 0x9e, (byte) 0x73, (byte) 0x44, (byte) 0x93, (byte) 0xb4, (byte) 0xf1,
+ (byte) 0x6b, (byte) 0x98, (byte) 0xa0, (byte) 0x57, (byte) 0xbb, (byte) 0x5e, (byte) 0x8f, (byte) 0x89,
+ (byte) 0x5b, (byte) 0x97, (byte) 0x26, (byte) 0xe4, (byte) 0xd0, (byte) 0x51, (byte) 0x0a, (byte) 0x5a,
+ (byte) 0xb7, (byte) 0x12, (byte) 0x1a, (byte) 0x6d, (byte) 0xb0, (byte) 0x79, (byte) 0x30, (byte) 0x51,
+ (byte) 0x83, (byte) 0x2e, (byte) 0xe2, (byte) 0x7a, (byte) 0x67, (byte) 0x66, (byte) 0xd3, (byte) 0x95,
+ (byte) 0xca, (byte) 0xfc, (byte) 0xcb, (byte) 0x92, (byte) 0x79, (byte) 0x32, (byte) 0x26, (byte) 0x86,
+ (byte) 0xe1, (byte) 0x0d, (byte) 0xd8, (byte) 0x19, (byte) 0xfa, (byte) 0x65, (byte) 0x37, (byte) 0xc9,
+ (byte) 0x4c, (byte) 0x2a, (byte) 0xe1, (byte) 0x42, (byte) 0xc7, (byte) 0xd4, (byte) 0xb7, (byte) 0xeb,
+ (byte) 0x1f, (byte) 0xc3, (byte) 0x53, (byte) 0x64, (byte) 0x6f, (byte) 0x2b, (byte) 0x78, (byte) 0x18,
+ (byte) 0x03, (byte) 0xda, (byte) 0x8d, (byte) 0x62, (byte) 0x24, (byte) 0x70, (byte) 0xab, (byte) 0xe6,
+ (byte) 0x16, (byte) 0x13, (byte) 0x24, (byte) 0x6b, (byte) 0x5f, (byte) 0xd3, (byte) 0xec, (byte) 0xc1,
+ (byte) 0x58, (byte) 0x64, (byte) 0xbd, (byte) 0x30, (byte) 0x98, (byte) 0x5e, (byte) 0x33, (byte) 0xce,
+ (byte) 0x87, (byte) 0x64, (byte) 0x14, (byte) 0x07, (byte) 0x85, (byte) 0x43, (byte) 0x3e, (byte) 0x9f,
+ (byte) 0x27, (byte) 0x9f, (byte) 0x63, (byte) 0x66, (byte) 0x9d, (byte) 0x26, (byte) 0x19, (byte) 0xc0,
+ (byte) 0x02, (byte) 0x08, (byte) 0x15, (byte) 0xcb, (byte) 0xb4, (byte) 0xaa, (byte) 0x4a, (byte) 0xc8,
+ (byte) 0xc0, (byte) 0x09, (byte) 0x15, (byte) 0x7d, (byte) 0x8a, (byte) 0x21, (byte) 0xbc, (byte) 0xa3,
+ };
+
+ private static final byte[] SHA256withRSA_Vector2Signature = new byte[] {
+ (byte) 0x18, (byte) 0x6e, (byte) 0x31, (byte) 0x1f, (byte) 0x1d, (byte) 0x44, (byte) 0x09, (byte) 0x3e,
+ (byte) 0xa0, (byte) 0xc4, (byte) 0x3d, (byte) 0xb4, (byte) 0x1b, (byte) 0xf2, (byte) 0xd8, (byte) 0xa4,
+ (byte) 0x59, (byte) 0xab, (byte) 0xb5, (byte) 0x37, (byte) 0x28, (byte) 0xb8, (byte) 0x94, (byte) 0x6b,
+ (byte) 0x6f, (byte) 0x13, (byte) 0x54, (byte) 0xff, (byte) 0xac, (byte) 0x15, (byte) 0x84, (byte) 0xd0,
+ (byte) 0xc9, (byte) 0x15, (byte) 0x5b, (byte) 0x69, (byte) 0x05, (byte) 0xf1, (byte) 0x44, (byte) 0xfd,
+ (byte) 0xde, (byte) 0xe8, (byte) 0xb4, (byte) 0x12, (byte) 0x59, (byte) 0x9e, (byte) 0x4c, (byte) 0x0b,
+ (byte) 0xd5, (byte) 0x49, (byte) 0x33, (byte) 0x28, (byte) 0xe0, (byte) 0xcb, (byte) 0x87, (byte) 0x85,
+ (byte) 0xd8, (byte) 0x18, (byte) 0x6f, (byte) 0xfe, (byte) 0xa2, (byte) 0x23, (byte) 0x82, (byte) 0xf0,
+ (byte) 0xe5, (byte) 0x39, (byte) 0x1b, (byte) 0x8c, (byte) 0x93, (byte) 0x11, (byte) 0x49, (byte) 0x72,
+ (byte) 0x2a, (byte) 0x5b, (byte) 0x25, (byte) 0xff, (byte) 0x4e, (byte) 0x88, (byte) 0x70, (byte) 0x9d,
+ (byte) 0x9d, (byte) 0xff, (byte) 0xe2, (byte) 0xc0, (byte) 0x7e, (byte) 0xc8, (byte) 0x03, (byte) 0x40,
+ (byte) 0xbe, (byte) 0x44, (byte) 0x09, (byte) 0xeb, (byte) 0x9e, (byte) 0x8e, (byte) 0x88, (byte) 0xe4,
+ (byte) 0x98, (byte) 0x82, (byte) 0x06, (byte) 0xa4, (byte) 0x9d, (byte) 0x63, (byte) 0x88, (byte) 0x65,
+ (byte) 0xa3, (byte) 0x8e, (byte) 0x0d, (byte) 0x22, (byte) 0xf3, (byte) 0x33, (byte) 0xf2, (byte) 0x40,
+ (byte) 0xe8, (byte) 0x91, (byte) 0x67, (byte) 0x72, (byte) 0x29, (byte) 0x1c, (byte) 0x08, (byte) 0xff,
+ (byte) 0x54, (byte) 0xa0, (byte) 0xcc, (byte) 0xad, (byte) 0x84, (byte) 0x88, (byte) 0x4b, (byte) 0x3b,
+ (byte) 0xef, (byte) 0xf9, (byte) 0x5e, (byte) 0xb3, (byte) 0x41, (byte) 0x6a, (byte) 0xbd, (byte) 0x94,
+ (byte) 0x16, (byte) 0x7d, (byte) 0x9d, (byte) 0x53, (byte) 0x77, (byte) 0xf1, (byte) 0x6a, (byte) 0x95,
+ (byte) 0x57, (byte) 0xad, (byte) 0x65, (byte) 0x9d, (byte) 0x75, (byte) 0x95, (byte) 0xf6, (byte) 0x6a,
+ (byte) 0xd2, (byte) 0x88, (byte) 0xea, (byte) 0x5b, (byte) 0xa2, (byte) 0x94, (byte) 0x8f, (byte) 0x5e,
+ (byte) 0x84, (byte) 0x18, (byte) 0x19, (byte) 0x46, (byte) 0x83, (byte) 0x0b, (byte) 0x6d, (byte) 0x5b,
+ (byte) 0xb9, (byte) 0xdb, (byte) 0xa4, (byte) 0xe5, (byte) 0x17, (byte) 0x02, (byte) 0x9e, (byte) 0x11,
+ (byte) 0xed, (byte) 0xd9, (byte) 0x7b, (byte) 0x83, (byte) 0x87, (byte) 0x89, (byte) 0xf3, (byte) 0xe4,
+ (byte) 0xbf, (byte) 0x0e, (byte) 0xe8, (byte) 0xdc, (byte) 0x55, (byte) 0x9c, (byte) 0xf7, (byte) 0xc9,
+ (byte) 0xc3, (byte) 0xe2, (byte) 0x2c, (byte) 0xf7, (byte) 0x8c, (byte) 0xaa, (byte) 0x17, (byte) 0x1f,
+ (byte) 0xd1, (byte) 0xc7, (byte) 0x74, (byte) 0xc7, (byte) 0x8e, (byte) 0x1c, (byte) 0x5b, (byte) 0xd2,
+ (byte) 0x31, (byte) 0x74, (byte) 0x43, (byte) 0x9a, (byte) 0x52, (byte) 0xbf, (byte) 0x89, (byte) 0xc5,
+ (byte) 0xb4, (byte) 0x80, (byte) 0x6a, (byte) 0x9e, (byte) 0x05, (byte) 0xdb, (byte) 0xbb, (byte) 0x07,
+ (byte) 0x8c, (byte) 0x08, (byte) 0x61, (byte) 0xba, (byte) 0xa4, (byte) 0xbc, (byte) 0x80, (byte) 0x3a,
+ (byte) 0xdd, (byte) 0x3b, (byte) 0x1a, (byte) 0x8c, (byte) 0x21, (byte) 0xd8, (byte) 0xa3, (byte) 0xc0,
+ (byte) 0xc7, (byte) 0xd1, (byte) 0x08, (byte) 0xe1, (byte) 0x34, (byte) 0x99, (byte) 0xc0, (byte) 0xcf,
+ (byte) 0x80, (byte) 0xff, (byte) 0xfa, (byte) 0x07, (byte) 0xef, (byte) 0x5c, (byte) 0x45, (byte) 0xe5,
+ };
+
+ private static final byte[] SHA384withRSA_Vector2Signature = new byte[] {
+ (byte) 0xaf, (byte) 0xf7, (byte) 0x7a, (byte) 0xc2, (byte) 0xbb, (byte) 0xb8, (byte) 0xbd, (byte) 0xe3,
+ (byte) 0x42, (byte) 0xaa, (byte) 0x16, (byte) 0x8a, (byte) 0x52, (byte) 0x6c, (byte) 0x99, (byte) 0x66,
+ (byte) 0x08, (byte) 0xbe, (byte) 0x15, (byte) 0xd9, (byte) 0x7c, (byte) 0x60, (byte) 0x2c, (byte) 0xac,
+ (byte) 0x4d, (byte) 0x4c, (byte) 0xf4, (byte) 0xdf, (byte) 0xbc, (byte) 0x16, (byte) 0x58, (byte) 0x0a,
+ (byte) 0x4e, (byte) 0xde, (byte) 0x8d, (byte) 0xb3, (byte) 0xbd, (byte) 0x03, (byte) 0x4e, (byte) 0x23,
+ (byte) 0x40, (byte) 0xa5, (byte) 0x80, (byte) 0xae, (byte) 0x83, (byte) 0xb4, (byte) 0x0f, (byte) 0x99,
+ (byte) 0x44, (byte) 0xc3, (byte) 0x5e, (byte) 0xdb, (byte) 0x59, (byte) 0x1d, (byte) 0xea, (byte) 0x7b,
+ (byte) 0x4d, (byte) 0xf3, (byte) 0xd2, (byte) 0xad, (byte) 0xbd, (byte) 0x21, (byte) 0x9f, (byte) 0x8e,
+ (byte) 0x87, (byte) 0x8f, (byte) 0x12, (byte) 0x13, (byte) 0x33, (byte) 0xf1, (byte) 0xc0, (byte) 0x9d,
+ (byte) 0xe7, (byte) 0xec, (byte) 0x6e, (byte) 0xad, (byte) 0xea, (byte) 0x5d, (byte) 0x69, (byte) 0xbb,
+ (byte) 0xab, (byte) 0x5b, (byte) 0xd8, (byte) 0x55, (byte) 0x56, (byte) 0xc8, (byte) 0xda, (byte) 0x81,
+ (byte) 0x41, (byte) 0xfb, (byte) 0xd3, (byte) 0x11, (byte) 0x6c, (byte) 0x97, (byte) 0xa7, (byte) 0xc3,
+ (byte) 0xf1, (byte) 0x31, (byte) 0xbf, (byte) 0xbe, (byte) 0x3f, (byte) 0xdb, (byte) 0x35, (byte) 0x85,
+ (byte) 0xb7, (byte) 0xb0, (byte) 0x75, (byte) 0x7f, (byte) 0xaf, (byte) 0xfb, (byte) 0x65, (byte) 0x61,
+ (byte) 0xc7, (byte) 0x0e, (byte) 0x63, (byte) 0xb5, (byte) 0x7d, (byte) 0x95, (byte) 0xe9, (byte) 0x16,
+ (byte) 0x9d, (byte) 0x6a, (byte) 0x00, (byte) 0x9f, (byte) 0x5e, (byte) 0xcd, (byte) 0xff, (byte) 0xa6,
+ (byte) 0xbc, (byte) 0x71, (byte) 0xf2, (byte) 0x2c, (byte) 0xd3, (byte) 0x68, (byte) 0xb9, (byte) 0x3f,
+ (byte) 0xaa, (byte) 0x06, (byte) 0xf1, (byte) 0x9c, (byte) 0x7e, (byte) 0xca, (byte) 0x4a, (byte) 0xfe,
+ (byte) 0xb1, (byte) 0x73, (byte) 0x19, (byte) 0x80, (byte) 0x05, (byte) 0xa6, (byte) 0x85, (byte) 0x14,
+ (byte) 0xda, (byte) 0x7a, (byte) 0x16, (byte) 0x7a, (byte) 0xc2, (byte) 0x46, (byte) 0x57, (byte) 0xa7,
+ (byte) 0xc0, (byte) 0xbf, (byte) 0xcd, (byte) 0xdc, (byte) 0x2f, (byte) 0x64, (byte) 0xf6, (byte) 0x6d,
+ (byte) 0xdc, (byte) 0xcb, (byte) 0x5a, (byte) 0x29, (byte) 0x95, (byte) 0x1c, (byte) 0xfe, (byte) 0xf2,
+ (byte) 0xda, (byte) 0x7e, (byte) 0xcb, (byte) 0x26, (byte) 0x12, (byte) 0xc6, (byte) 0xb0, (byte) 0xba,
+ (byte) 0x84, (byte) 0x9b, (byte) 0x4f, (byte) 0xba, (byte) 0x1b, (byte) 0x78, (byte) 0x25, (byte) 0xb8,
+ (byte) 0x8f, (byte) 0x2e, (byte) 0x51, (byte) 0x5f, (byte) 0x9e, (byte) 0xfc, (byte) 0x40, (byte) 0xbc,
+ (byte) 0x85, (byte) 0xcd, (byte) 0x86, (byte) 0x7f, (byte) 0x88, (byte) 0xc5, (byte) 0xaa, (byte) 0x2b,
+ (byte) 0x78, (byte) 0xb1, (byte) 0x9c, (byte) 0x51, (byte) 0x9a, (byte) 0xe1, (byte) 0xe1, (byte) 0xc0,
+ (byte) 0x40, (byte) 0x47, (byte) 0xcb, (byte) 0xa4, (byte) 0xb7, (byte) 0x6c, (byte) 0x31, (byte) 0xf2,
+ (byte) 0xc8, (byte) 0x9a, (byte) 0xad, (byte) 0x0b, (byte) 0xd3, (byte) 0xf6, (byte) 0x85, (byte) 0x9a,
+ (byte) 0x8f, (byte) 0x4f, (byte) 0xc9, (byte) 0xd8, (byte) 0x33, (byte) 0x7c, (byte) 0x45, (byte) 0x30,
+ (byte) 0xea, (byte) 0x17, (byte) 0xd3, (byte) 0xe3, (byte) 0x90, (byte) 0x2c, (byte) 0xda, (byte) 0xde,
+ (byte) 0x41, (byte) 0x17, (byte) 0x3f, (byte) 0x08, (byte) 0xb9, (byte) 0x34, (byte) 0xc0, (byte) 0xd1,
+ };
+
+ private static final byte[] SHA512withRSA_Vector2Signature = new byte[] {
+ (byte) 0x19, (byte) 0xe2, (byte) 0xe5, (byte) 0xf3, (byte) 0x18, (byte) 0x83, (byte) 0xec, (byte) 0xf0,
+ (byte) 0xab, (byte) 0x50, (byte) 0x05, (byte) 0x4b, (byte) 0x5f, (byte) 0x22, (byte) 0xfc, (byte) 0x82,
+ (byte) 0x6d, (byte) 0xca, (byte) 0xe7, (byte) 0xbe, (byte) 0x23, (byte) 0x94, (byte) 0xfa, (byte) 0xf9,
+ (byte) 0xa4, (byte) 0x8a, (byte) 0x95, (byte) 0x4d, (byte) 0x14, (byte) 0x08, (byte) 0x8b, (byte) 0x5e,
+ (byte) 0x03, (byte) 0x1b, (byte) 0x74, (byte) 0xde, (byte) 0xc1, (byte) 0x45, (byte) 0x9c, (byte) 0xce,
+ (byte) 0x1d, (byte) 0xac, (byte) 0xab, (byte) 0xd3, (byte) 0xa8, (byte) 0xc3, (byte) 0xca, (byte) 0x67,
+ (byte) 0x80, (byte) 0xf6, (byte) 0x03, (byte) 0x46, (byte) 0x65, (byte) 0x77, (byte) 0x59, (byte) 0xbb,
+ (byte) 0xb8, (byte) 0x83, (byte) 0xee, (byte) 0xc2, (byte) 0x3e, (byte) 0x78, (byte) 0xdd, (byte) 0x89,
+ (byte) 0xcd, (byte) 0x9b, (byte) 0x78, (byte) 0x35, (byte) 0xa9, (byte) 0x09, (byte) 0xc8, (byte) 0x77,
+ (byte) 0xdd, (byte) 0xd3, (byte) 0xa0, (byte) 0x64, (byte) 0xb0, (byte) 0x74, (byte) 0x48, (byte) 0x51,
+ (byte) 0x4f, (byte) 0xa0, (byte) 0xae, (byte) 0x33, (byte) 0xb3, (byte) 0x28, (byte) 0xb0, (byte) 0xa8,
+ (byte) 0x78, (byte) 0x8f, (byte) 0xa2, (byte) 0x32, (byte) 0xa6, (byte) 0x0a, (byte) 0xaa, (byte) 0x09,
+ (byte) 0xb5, (byte) 0x8d, (byte) 0x4c, (byte) 0x44, (byte) 0x46, (byte) 0xb4, (byte) 0xd2, (byte) 0x06,
+ (byte) 0x6b, (byte) 0x8c, (byte) 0x51, (byte) 0x6e, (byte) 0x9c, (byte) 0xfa, (byte) 0x1f, (byte) 0x94,
+ (byte) 0x3e, (byte) 0x19, (byte) 0x9c, (byte) 0x63, (byte) 0xfe, (byte) 0xa9, (byte) 0x9a, (byte) 0xe3,
+ (byte) 0x6c, (byte) 0x82, (byte) 0x64, (byte) 0x5f, (byte) 0xca, (byte) 0xc2, (byte) 0x8d, (byte) 0x66,
+ (byte) 0xbe, (byte) 0x12, (byte) 0x6e, (byte) 0xb6, (byte) 0x35, (byte) 0x6d, (byte) 0xaa, (byte) 0xed,
+ (byte) 0x4b, (byte) 0x50, (byte) 0x08, (byte) 0x1c, (byte) 0xbf, (byte) 0x07, (byte) 0x70, (byte) 0x78,
+ (byte) 0xc0, (byte) 0xbb, (byte) 0xc5, (byte) 0x8d, (byte) 0x6c, (byte) 0x8d, (byte) 0x35, (byte) 0xff,
+ (byte) 0x04, (byte) 0x81, (byte) 0xd8, (byte) 0xf4, (byte) 0xd2, (byte) 0x4a, (byte) 0xc3, (byte) 0x05,
+ (byte) 0x23, (byte) 0xcb, (byte) 0xeb, (byte) 0x20, (byte) 0xb1, (byte) 0xd4, (byte) 0x2d, (byte) 0xd8,
+ (byte) 0x7a, (byte) 0xd4, (byte) 0x7e, (byte) 0xf6, (byte) 0xa9, (byte) 0xe8, (byte) 0x72, (byte) 0x69,
+ (byte) 0xfe, (byte) 0xab, (byte) 0x54, (byte) 0x4d, (byte) 0xd1, (byte) 0xf4, (byte) 0x6b, (byte) 0x83,
+ (byte) 0x31, (byte) 0x17, (byte) 0xed, (byte) 0x26, (byte) 0xe9, (byte) 0xd2, (byte) 0x5b, (byte) 0xad,
+ (byte) 0x42, (byte) 0x42, (byte) 0xa5, (byte) 0x8f, (byte) 0x98, (byte) 0x7c, (byte) 0x1b, (byte) 0x5c,
+ (byte) 0x8e, (byte) 0x88, (byte) 0x56, (byte) 0x20, (byte) 0x8e, (byte) 0x48, (byte) 0xf9, (byte) 0x4d,
+ (byte) 0x82, (byte) 0x91, (byte) 0xcb, (byte) 0xc8, (byte) 0x1c, (byte) 0x7c, (byte) 0xa5, (byte) 0x69,
+ (byte) 0x1b, (byte) 0x40, (byte) 0xc2, (byte) 0x4c, (byte) 0x25, (byte) 0x16, (byte) 0x4f, (byte) 0xfa,
+ (byte) 0x09, (byte) 0xeb, (byte) 0xf5, (byte) 0x6c, (byte) 0x55, (byte) 0x3c, (byte) 0x6e, (byte) 0xf7,
+ (byte) 0xc0, (byte) 0xc1, (byte) 0x34, (byte) 0xd1, (byte) 0x53, (byte) 0xa3, (byte) 0x69, (byte) 0x64,
+ (byte) 0xee, (byte) 0xf4, (byte) 0xf9, (byte) 0xc7, (byte) 0x96, (byte) 0x60, (byte) 0x84, (byte) 0x87,
+ (byte) 0xb4, (byte) 0xc7, (byte) 0x3c, (byte) 0x26, (byte) 0xa7, (byte) 0x3a, (byte) 0xbf, (byte) 0x95,
+ };
+
+ private static final byte[] MD5withRSA_Vector2Signature = new byte[] {
+ (byte) 0x04, (byte) 0x17, (byte) 0x83, (byte) 0x10, (byte) 0xe2, (byte) 0x6e, (byte) 0xdf, (byte) 0xa9,
+ (byte) 0xae, (byte) 0xd2, (byte) 0xdc, (byte) 0x5f, (byte) 0x70, (byte) 0x1d, (byte) 0xaf, (byte) 0x54,
+ (byte) 0xc0, (byte) 0x5f, (byte) 0x0b, (byte) 0x2c, (byte) 0xe6, (byte) 0xd0, (byte) 0x00, (byte) 0x18,
+ (byte) 0x4c, (byte) 0xf6, (byte) 0x8f, (byte) 0x18, (byte) 0x10, (byte) 0x74, (byte) 0x90, (byte) 0x99,
+ (byte) 0xa9, (byte) 0x90, (byte) 0x3c, (byte) 0x5a, (byte) 0x38, (byte) 0xd3, (byte) 0x3d, (byte) 0x48,
+ (byte) 0xcf, (byte) 0x31, (byte) 0xaf, (byte) 0x12, (byte) 0x98, (byte) 0xfb, (byte) 0x66, (byte) 0xe8,
+ (byte) 0x58, (byte) 0xec, (byte) 0xca, (byte) 0xe1, (byte) 0x42, (byte) 0xf9, (byte) 0x84, (byte) 0x17,
+ (byte) 0x6f, (byte) 0x4c, (byte) 0x3e, (byte) 0xc4, (byte) 0x40, (byte) 0xc6, (byte) 0x70, (byte) 0xb0,
+ (byte) 0x38, (byte) 0xf3, (byte) 0x47, (byte) 0xeb, (byte) 0x6f, (byte) 0xcb, (byte) 0xea, (byte) 0x21,
+ (byte) 0x41, (byte) 0xf3, (byte) 0xa0, (byte) 0x3e, (byte) 0x42, (byte) 0xad, (byte) 0xa5, (byte) 0xad,
+ (byte) 0x5d, (byte) 0x2c, (byte) 0x1a, (byte) 0x8e, (byte) 0x3e, (byte) 0xb3, (byte) 0xa5, (byte) 0x78,
+ (byte) 0x3d, (byte) 0x56, (byte) 0x09, (byte) 0x93, (byte) 0xc9, (byte) 0x93, (byte) 0xd3, (byte) 0xd2,
+ (byte) 0x9a, (byte) 0xc5, (byte) 0xa5, (byte) 0x2e, (byte) 0xb2, (byte) 0xd8, (byte) 0x37, (byte) 0xc7,
+ (byte) 0x13, (byte) 0x1a, (byte) 0x0b, (byte) 0xda, (byte) 0x50, (byte) 0x28, (byte) 0x6d, (byte) 0x47,
+ (byte) 0x65, (byte) 0x52, (byte) 0xcd, (byte) 0xe7, (byte) 0xec, (byte) 0x57, (byte) 0x00, (byte) 0x41,
+ (byte) 0x34, (byte) 0x28, (byte) 0xb9, (byte) 0x8b, (byte) 0x03, (byte) 0x41, (byte) 0xb6, (byte) 0xd5,
+ (byte) 0xa8, (byte) 0xef, (byte) 0xd3, (byte) 0xdd, (byte) 0x80, (byte) 0xd5, (byte) 0x69, (byte) 0xe4,
+ (byte) 0xf0, (byte) 0x4d, (byte) 0xa4, (byte) 0x7d, (byte) 0x60, (byte) 0x2f, (byte) 0xef, (byte) 0x79,
+ (byte) 0x07, (byte) 0x75, (byte) 0xeb, (byte) 0xf7, (byte) 0x4b, (byte) 0x43, (byte) 0x41, (byte) 0xdb,
+ (byte) 0x33, (byte) 0xad, (byte) 0x9c, (byte) 0x7b, (byte) 0x78, (byte) 0x83, (byte) 0x34, (byte) 0x77,
+ (byte) 0xe4, (byte) 0x80, (byte) 0xbe, (byte) 0xe6, (byte) 0x6f, (byte) 0xdd, (byte) 0xac, (byte) 0xa5,
+ (byte) 0x37, (byte) 0xcf, (byte) 0xb5, (byte) 0x44, (byte) 0x11, (byte) 0x77, (byte) 0x96, (byte) 0x45,
+ (byte) 0xf9, (byte) 0xae, (byte) 0x48, (byte) 0xa6, (byte) 0xbe, (byte) 0x30, (byte) 0x32, (byte) 0xeb,
+ (byte) 0x43, (byte) 0x6f, (byte) 0x66, (byte) 0x39, (byte) 0x57, (byte) 0xf8, (byte) 0xe6, (byte) 0x60,
+ (byte) 0x31, (byte) 0xd0, (byte) 0xfc, (byte) 0xcf, (byte) 0x9f, (byte) 0xe5, (byte) 0x3d, (byte) 0xcf,
+ (byte) 0xbd, (byte) 0x7b, (byte) 0x13, (byte) 0x20, (byte) 0xce, (byte) 0x11, (byte) 0xfd, (byte) 0xe5,
+ (byte) 0xff, (byte) 0x90, (byte) 0x85, (byte) 0xdf, (byte) 0xca, (byte) 0x3d, (byte) 0xd9, (byte) 0x44,
+ (byte) 0x16, (byte) 0xc2, (byte) 0x32, (byte) 0x28, (byte) 0xc7, (byte) 0x01, (byte) 0x6d, (byte) 0xea,
+ (byte) 0xcb, (byte) 0x0d, (byte) 0x85, (byte) 0x08, (byte) 0x6f, (byte) 0xcb, (byte) 0x41, (byte) 0x6a,
+ (byte) 0x3c, (byte) 0x0f, (byte) 0x3d, (byte) 0x38, (byte) 0xb5, (byte) 0x61, (byte) 0xc5, (byte) 0x64,
+ (byte) 0x64, (byte) 0x81, (byte) 0x4c, (byte) 0xcd, (byte) 0xd1, (byte) 0x6a, (byte) 0x87, (byte) 0x28,
+ (byte) 0x02, (byte) 0xaf, (byte) 0x8f, (byte) 0x59, (byte) 0xe5, (byte) 0x67, (byte) 0x25, (byte) 0x00,
+ };
+
+ public void testGetCommonInstances_Success() throws Exception {
+ assertNotNull(Signature.getInstance("SHA1withRSA"));
+ assertNotNull(Signature.getInstance("SHA256withRSA"));
+ assertNotNull(Signature.getInstance("SHA384withRSA"));
+ assertNotNull(Signature.getInstance("SHA512withRSA"));
+ assertNotNull(Signature.getInstance("MD5withRSA"));
+ assertNotNull(Signature.getInstance("SHA1withDSA"));
+ }
+
+ public void testVerify_SHA1withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector1Signature));
+ }
+
+ public void testVerify_SHA256withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA256withRSA_Vector2Signature));
+ }
+
+ public void testVerify_SHA384withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA384withRSA_Vector2Signature));
+ }
+
+ public void testVerify_SHA512withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA512withRSA_Vector2Signature));
+ }
+
+ public void testVerify_MD5withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("MD5withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(MD5withRSA_Vector2Signature));
+ }
+
+ public void testVerify_SHA1withRSA_Key_InitSignThenInitVerify_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(privKeySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ // Start a signing operation
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ // Switch to verify
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertTrue("Signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector1Signature));
+ }
+
+ public void testVerify_SHA1withRSA_Key_TwoMessages_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(pubKey);
+
+ sig.update(Vector1Data);
+ assertTrue("First signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector1Signature));
+
+ sig.update(Vector2Data);
+ assertTrue("Second signature must match expected signature",
+ sig.verify(SHA1withRSA_Vector2Signature));
+ }
+
+ public void testVerify_SHA1withRSA_Key_WrongExpectedSignature_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+
+ assertFalse("Signature should fail to verify", sig.verify(SHA1withRSA_Vector2Signature));
+ }
+
+ public void testSign_SHA1withRSA_CrtKeyWithPublicExponent_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, RSA_2048_privateExponent, null, null, null, null, null);
+
+ // The RI fails on this key which is totally unreasonable.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ if (StandardNames.IS_RI) {
+ return;
+ } else {
+ fail("Private key should be created");
+ return;
+ }
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector1Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA1withRSA_Vector1Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testSign_SHA1withRSA_CrtKey_NoPrivateExponent_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, null, RSA_2048_primeP, RSA_2048_primeQ, null, null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when private exponent is not available");
+ } catch (InvalidKeyException e) {
+ // success
+ }
+ }
+
+ public void testSign_SHA1withRSA_CrtKey_NoModulus_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(null, RSA_2048_publicExponent,
+ RSA_2048_privateExponent, RSA_2048_primeP, RSA_2048_primeQ, null, null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when modulus is not available");
+ } catch (InvalidKeyException e) {
+ // success
+ }
+ }
+
+ public void testSign_SHA1withRSA_Key_EmptyKey_Failure() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(null, null);
+
+ // Failing on this key early is okay.
+ final PrivateKey privKey;
+ try {
+ privKey = kf.generatePrivate(keySpec);
+ } catch (NullPointerException e) {
+ return;
+ } catch (InvalidKeySpecException e) {
+ return;
+ }
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+
+ try {
+ sig.initSign(privKey);
+ fail("Should throw error when key is empty");
+ } catch (InvalidKeyException e) {
+ // success
+ }
+ }
+
+ public void testSign_SHA1withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector1Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA1withRSA_Vector1Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector1Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testSign_SHA256withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+
+ final PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA256withRSA_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testSign_SHA384withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA384withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA384withRSA_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testSign_SHA512withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA512withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, SHA512withRSA_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testSign_MD5withRSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
+ RSA_2048_privateExponent);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("MD5withRSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+ assertTrue("Signature should match expected",
+ Arrays.equals(signature, MD5withRSA_Vector2Signature));
+
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ /*
+ * These tests were generated with this DSA private key:
+ *
+ * -----BEGIN DSA PRIVATE KEY-----
+ * MIIBugIBAAKBgQCeYcKJ73epThNnZB8JAf4kE1Pgt5CoTnb+iYJ/esU8TgwgVTCV
+ * QoXhQH0njwcN6NyZ77MHlDTWfP+cvmnT60Q3UO9J+OJb2NEQhJfq46UcwE5pynA9
+ * eLkW5f5hXYpasyxhtgE70AF8Mo3h82kOi1jGzwCU+EkqS+raAP9L0L5AIwIVAL/u
+ * qg8SNFBy+GAT2PFBARClL1dfAoGAd9R6EsyBfn7rOvvmhm1aEB2tqU+5A10hGuQw
+ * lXWOzV7RvQpF7uf3a2UCYNAurz28B90rjjPAk4DZK6dxV3a8jrng1/QjjUEal08s
+ * G9VLZuj60lANF6s0MT2kiNiOqKduFwO3D2h8ZHuSuGPkmmcYgSfUCxNI031O9qiP
+ * VhctCFECgYAz7i1DhjRGUkCdYQd5tVaI42lhXOV71MTYPbuFOIxTL/hny7Z0PZWR
+ * A1blmYE6vrArDEhzpmRvDJZSIMzMfJjUIGu1KO73zpo9siK0xY0/sw5r3QC9txP2
+ * 2Mv3BUIl5TLrs9outQJ0VMwldY2fElgCLWcSVkH44qZwWir1cq+cIwIUEGPDardb
+ * pNvWlWgTDD6a6ZTby+M=
+ * -----END DSA PRIVATE KEY-----
+ *
+ */
+
+ private static final BigInteger DSA_priv = new BigInteger(new byte[] {
+ (byte) 0x10, (byte) 0x63, (byte) 0xc3, (byte) 0x6a, (byte) 0xb7, (byte) 0x5b, (byte) 0xa4, (byte) 0xdb,
+ (byte) 0xd6, (byte) 0x95, (byte) 0x68, (byte) 0x13, (byte) 0x0c, (byte) 0x3e, (byte) 0x9a, (byte) 0xe9,
+ (byte) 0x94, (byte) 0xdb, (byte) 0xcb, (byte) 0xe3,
+ });
+
+ private static final BigInteger DSA_pub = new BigInteger(new byte[] {
+ (byte) 0x33, (byte) 0xee, (byte) 0x2d, (byte) 0x43, (byte) 0x86, (byte) 0x34, (byte) 0x46, (byte) 0x52,
+ (byte) 0x40, (byte) 0x9d, (byte) 0x61, (byte) 0x07, (byte) 0x79, (byte) 0xb5, (byte) 0x56, (byte) 0x88,
+ (byte) 0xe3, (byte) 0x69, (byte) 0x61, (byte) 0x5c, (byte) 0xe5, (byte) 0x7b, (byte) 0xd4, (byte) 0xc4,
+ (byte) 0xd8, (byte) 0x3d, (byte) 0xbb, (byte) 0x85, (byte) 0x38, (byte) 0x8c, (byte) 0x53, (byte) 0x2f,
+ (byte) 0xf8, (byte) 0x67, (byte) 0xcb, (byte) 0xb6, (byte) 0x74, (byte) 0x3d, (byte) 0x95, (byte) 0x91,
+ (byte) 0x03, (byte) 0x56, (byte) 0xe5, (byte) 0x99, (byte) 0x81, (byte) 0x3a, (byte) 0xbe, (byte) 0xb0,
+ (byte) 0x2b, (byte) 0x0c, (byte) 0x48, (byte) 0x73, (byte) 0xa6, (byte) 0x64, (byte) 0x6f, (byte) 0x0c,
+ (byte) 0x96, (byte) 0x52, (byte) 0x20, (byte) 0xcc, (byte) 0xcc, (byte) 0x7c, (byte) 0x98, (byte) 0xd4,
+ (byte) 0x20, (byte) 0x6b, (byte) 0xb5, (byte) 0x28, (byte) 0xee, (byte) 0xf7, (byte) 0xce, (byte) 0x9a,
+ (byte) 0x3d, (byte) 0xb2, (byte) 0x22, (byte) 0xb4, (byte) 0xc5, (byte) 0x8d, (byte) 0x3f, (byte) 0xb3,
+ (byte) 0x0e, (byte) 0x6b, (byte) 0xdd, (byte) 0x00, (byte) 0xbd, (byte) 0xb7, (byte) 0x13, (byte) 0xf6,
+ (byte) 0xd8, (byte) 0xcb, (byte) 0xf7, (byte) 0x05, (byte) 0x42, (byte) 0x25, (byte) 0xe5, (byte) 0x32,
+ (byte) 0xeb, (byte) 0xb3, (byte) 0xda, (byte) 0x2e, (byte) 0xb5, (byte) 0x02, (byte) 0x74, (byte) 0x54,
+ (byte) 0xcc, (byte) 0x25, (byte) 0x75, (byte) 0x8d, (byte) 0x9f, (byte) 0x12, (byte) 0x58, (byte) 0x02,
+ (byte) 0x2d, (byte) 0x67, (byte) 0x12, (byte) 0x56, (byte) 0x41, (byte) 0xf8, (byte) 0xe2, (byte) 0xa6,
+ (byte) 0x70, (byte) 0x5a, (byte) 0x2a, (byte) 0xf5, (byte) 0x72, (byte) 0xaf, (byte) 0x9c, (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_P = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0x9e, (byte) 0x61, (byte) 0xc2, (byte) 0x89, (byte) 0xef, (byte) 0x77, (byte) 0xa9,
+ (byte) 0x4e, (byte) 0x13, (byte) 0x67, (byte) 0x64, (byte) 0x1f, (byte) 0x09, (byte) 0x01, (byte) 0xfe,
+ (byte) 0x24, (byte) 0x13, (byte) 0x53, (byte) 0xe0, (byte) 0xb7, (byte) 0x90, (byte) 0xa8, (byte) 0x4e,
+ (byte) 0x76, (byte) 0xfe, (byte) 0x89, (byte) 0x82, (byte) 0x7f, (byte) 0x7a, (byte) 0xc5, (byte) 0x3c,
+ (byte) 0x4e, (byte) 0x0c, (byte) 0x20, (byte) 0x55, (byte) 0x30, (byte) 0x95, (byte) 0x42, (byte) 0x85,
+ (byte) 0xe1, (byte) 0x40, (byte) 0x7d, (byte) 0x27, (byte) 0x8f, (byte) 0x07, (byte) 0x0d, (byte) 0xe8,
+ (byte) 0xdc, (byte) 0x99, (byte) 0xef, (byte) 0xb3, (byte) 0x07, (byte) 0x94, (byte) 0x34, (byte) 0xd6,
+ (byte) 0x7c, (byte) 0xff, (byte) 0x9c, (byte) 0xbe, (byte) 0x69, (byte) 0xd3, (byte) 0xeb, (byte) 0x44,
+ (byte) 0x37, (byte) 0x50, (byte) 0xef, (byte) 0x49, (byte) 0xf8, (byte) 0xe2, (byte) 0x5b, (byte) 0xd8,
+ (byte) 0xd1, (byte) 0x10, (byte) 0x84, (byte) 0x97, (byte) 0xea, (byte) 0xe3, (byte) 0xa5, (byte) 0x1c,
+ (byte) 0xc0, (byte) 0x4e, (byte) 0x69, (byte) 0xca, (byte) 0x70, (byte) 0x3d, (byte) 0x78, (byte) 0xb9,
+ (byte) 0x16, (byte) 0xe5, (byte) 0xfe, (byte) 0x61, (byte) 0x5d, (byte) 0x8a, (byte) 0x5a, (byte) 0xb3,
+ (byte) 0x2c, (byte) 0x61, (byte) 0xb6, (byte) 0x01, (byte) 0x3b, (byte) 0xd0, (byte) 0x01, (byte) 0x7c,
+ (byte) 0x32, (byte) 0x8d, (byte) 0xe1, (byte) 0xf3, (byte) 0x69, (byte) 0x0e, (byte) 0x8b, (byte) 0x58,
+ (byte) 0xc6, (byte) 0xcf, (byte) 0x00, (byte) 0x94, (byte) 0xf8, (byte) 0x49, (byte) 0x2a, (byte) 0x4b,
+ (byte) 0xea, (byte) 0xda, (byte) 0x00, (byte) 0xff, (byte) 0x4b, (byte) 0xd0, (byte) 0xbe, (byte) 0x40,
+ (byte) 0x23,
+ });
+
+ private static final BigInteger DSA_Q = new BigInteger(new byte[] {
+ (byte) 0x00, (byte) 0xbf, (byte) 0xee, (byte) 0xaa, (byte) 0x0f, (byte) 0x12, (byte) 0x34, (byte) 0x50,
+ (byte) 0x72, (byte) 0xf8, (byte) 0x60, (byte) 0x13, (byte) 0xd8, (byte) 0xf1, (byte) 0x41, (byte) 0x01,
+ (byte) 0x10, (byte) 0xa5, (byte) 0x2f, (byte) 0x57, (byte) 0x5f,
+ });
+
+ private static final BigInteger DSA_G = new BigInteger(new byte[] {
+ (byte) 0x77, (byte) 0xd4, (byte) 0x7a, (byte) 0x12, (byte) 0xcc, (byte) 0x81, (byte) 0x7e, (byte) 0x7e,
+ (byte) 0xeb, (byte) 0x3a, (byte) 0xfb, (byte) 0xe6, (byte) 0x86, (byte) 0x6d, (byte) 0x5a, (byte) 0x10,
+ (byte) 0x1d, (byte) 0xad, (byte) 0xa9, (byte) 0x4f, (byte) 0xb9, (byte) 0x03, (byte) 0x5d, (byte) 0x21,
+ (byte) 0x1a, (byte) 0xe4, (byte) 0x30, (byte) 0x95, (byte) 0x75, (byte) 0x8e, (byte) 0xcd, (byte) 0x5e,
+ (byte) 0xd1, (byte) 0xbd, (byte) 0x0a, (byte) 0x45, (byte) 0xee, (byte) 0xe7, (byte) 0xf7, (byte) 0x6b,
+ (byte) 0x65, (byte) 0x02, (byte) 0x60, (byte) 0xd0, (byte) 0x2e, (byte) 0xaf, (byte) 0x3d, (byte) 0xbc,
+ (byte) 0x07, (byte) 0xdd, (byte) 0x2b, (byte) 0x8e, (byte) 0x33, (byte) 0xc0, (byte) 0x93, (byte) 0x80,
+ (byte) 0xd9, (byte) 0x2b, (byte) 0xa7, (byte) 0x71, (byte) 0x57, (byte) 0x76, (byte) 0xbc, (byte) 0x8e,
+ (byte) 0xb9, (byte) 0xe0, (byte) 0xd7, (byte) 0xf4, (byte) 0x23, (byte) 0x8d, (byte) 0x41, (byte) 0x1a,
+ (byte) 0x97, (byte) 0x4f, (byte) 0x2c, (byte) 0x1b, (byte) 0xd5, (byte) 0x4b, (byte) 0x66, (byte) 0xe8,
+ (byte) 0xfa, (byte) 0xd2, (byte) 0x50, (byte) 0x0d, (byte) 0x17, (byte) 0xab, (byte) 0x34, (byte) 0x31,
+ (byte) 0x3d, (byte) 0xa4, (byte) 0x88, (byte) 0xd8, (byte) 0x8e, (byte) 0xa8, (byte) 0xa7, (byte) 0x6e,
+ (byte) 0x17, (byte) 0x03, (byte) 0xb7, (byte) 0x0f, (byte) 0x68, (byte) 0x7c, (byte) 0x64, (byte) 0x7b,
+ (byte) 0x92, (byte) 0xb8, (byte) 0x63, (byte) 0xe4, (byte) 0x9a, (byte) 0x67, (byte) 0x18, (byte) 0x81,
+ (byte) 0x27, (byte) 0xd4, (byte) 0x0b, (byte) 0x13, (byte) 0x48, (byte) 0xd3, (byte) 0x7d, (byte) 0x4e,
+ (byte) 0xf6, (byte) 0xa8, (byte) 0x8f, (byte) 0x56, (byte) 0x17, (byte) 0x2d, (byte) 0x08, (byte) 0x51,
+ });
+
+ /**
+ * A possible signature using SHA1withDSA of Vector2Data. Note that DSS is
+ * randomized, so this won't be the exact signature you'll get out of
+ * another signing operation unless you use a fixed RNG.
+ */
+ public static final byte[] SHA1withDSA_Vector2Signature = new byte[] {
+ (byte) 0x30, (byte) 0x2d, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0x88, (byte) 0xef, (byte) 0xac,
+ (byte) 0x2b, (byte) 0x8b, (byte) 0xe2, (byte) 0x61, (byte) 0xc6, (byte) 0x2b, (byte) 0xea, (byte) 0xd5,
+ (byte) 0x96, (byte) 0xbc, (byte) 0xb0, (byte) 0xa1, (byte) 0x30, (byte) 0x0c, (byte) 0x1f, (byte) 0xed,
+ (byte) 0x11, (byte) 0x02, (byte) 0x14, (byte) 0x15, (byte) 0xc4, (byte) 0xfc, (byte) 0x82, (byte) 0x6f,
+ (byte) 0x17, (byte) 0xdc, (byte) 0x87, (byte) 0x82, (byte) 0x75, (byte) 0x23, (byte) 0xd4, (byte) 0x58,
+ (byte) 0xdc, (byte) 0x73, (byte) 0x3d, (byte) 0xf3, (byte) 0x51, (byte) 0xc0, (byte) 0x57,
+ };
+
+ public void testSign_SHA1withDSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPrivateKeySpec keySpec = new DSAPrivateKeySpec(DSA_priv, DSA_P, DSA_Q, DSA_G);
+ PrivateKey privKey = kf.generatePrivate(keySpec);
+
+ Signature sig = Signature.getInstance("SHA1withDSA");
+ sig.initSign(privKey);
+ sig.update(Vector2Data);
+
+ byte[] signature = sig.sign();
+ assertNotNull("Signature must not be null", signature);
+
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(signature));
+ }
+
+ public void testVerify_SHA1withDSA_Key_Success() throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("DSA");
+ DSAPublicKeySpec pubKeySpec = new DSAPublicKeySpec(DSA_pub, DSA_P, DSA_Q, DSA_G);
+ PublicKey pubKey = kf.generatePublic(pubKeySpec);
+
+ Signature sig = Signature.getInstance("SHA1withDSA");
+ sig.initVerify(pubKey);
+ sig.update(Vector2Data);
+ assertTrue("Signature must verify correctly", sig.verify(SHA1withDSA_Vector2Signature));
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/AttributedCharacterIteratorAttributeTest.java b/luni/src/test/java/libcore/java/text/AttributedCharacterIteratorAttributeTest.java
index cca00f5..560a6b6 100644
--- a/luni/src/test/java/libcore/java/text/AttributedCharacterIteratorAttributeTest.java
+++ b/luni/src/test/java/libcore/java/text/AttributedCharacterIteratorAttributeTest.java
@@ -16,18 +16,13 @@
package libcore.java.text;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InvalidObjectException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.text.AttributedCharacterIterator;
import java.text.DateFormat;
import java.text.NumberFormat;
import junit.framework.TestCase;
-import tests.util.SerializationTester;
+import libcore.util.SerializationTester;
/**
* AttributedCharacterIterator.Attribute is used like the base enum type and
@@ -45,14 +40,14 @@
public void testSerializingSubclass() throws IOException, ClassNotFoundException {
AttributedCharacterIterator.Attribute a = new CustomAttribute();
try {
- SerializationTester.getDeserializedObject(a);
+ SerializationTester.reserialize(a);
fail();
} catch (InvalidObjectException expected) {
}
}
private void assertSameReserialized(Object o) throws ClassNotFoundException, IOException {
- assertSame(o, SerializationTester.getDeserializedObject(o));
+ assertSame(o, SerializationTester.reserialize(o));
}
private static class CustomAttribute extends AttributedCharacterIterator.Attribute {
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index 96c9aef..5c36fe2 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -20,6 +20,7 @@
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
+import libcore.util.SerializationTester;
public class CalendarTest extends junit.framework.TestCase {
@@ -186,9 +187,9 @@
+ "10000000500000001000000200000000178";
Calendar calendar = new GregorianCalendar(1970, 1, 1, 0, 0, 0);
calendar.setTimeZone(TimeZone.getTimeZone("GMT-08:00"));
- calendar.setFirstDayOfWeek(1);
+ // Starting from ICU4.8 release, the default minimalDaysInFirstWeek changed from 4 to 1.
calendar.setMinimalDaysInFirstWeek(4);
- new SerializableTester<Calendar>(calendar, s).test();
+ new SerializationTester<Calendar>(calendar, s).test();
}
private void assertCalendarEquals(Calendar calendar,
diff --git a/luni/src/test/java/libcore/java/util/EnumSetTest.java b/luni/src/test/java/libcore/java/util/EnumSetTest.java
new file mode 100644
index 0000000..a74e9fc
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/EnumSetTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 libcore.java.util;
+
+import java.io.InvalidObjectException;
+import java.util.EnumSet;
+import junit.framework.TestCase;
+import libcore.util.SerializationTester;
+
+public final class EnumSetTest extends TestCase {
+ public void testSmallEnumSetSerialization() {
+ assertTrue(Roshambo.values().length <= 64);
+ String s = "aced0005737200246a6176612e7574696c2e456e756d5365742453657269616c"
+ + "697a6174696f6e50726f78790507d3db7654cad10200024c000b656c656d656e7"
+ + "4547970657400114c6a6176612f6c616e672f436c6173733b5b0008656c656d65"
+ + "6e74737400115b4c6a6176612f6c616e672f456e756d3b7870767200266c69626"
+ + "36f72652e6a6176612e7574696c2e456e756d5365745465737424526f7368616d"
+ + "626f00000000000000001200007872000e6a6176612e6c616e672e456e756d000"
+ + "00000000000001200007870757200115b4c6a6176612e6c616e672e456e756d3b"
+ + "a88dea2d33d22f980200007870000000027e71007e0004740004524f434b7e710"
+ + "07e000474000853434953534f5253";
+ EnumSet<Roshambo> set = EnumSet.of(Roshambo.ROCK, Roshambo.SCISSORS);
+ new SerializationTester<EnumSet<Roshambo>>(set, s).test();
+ }
+
+ public void testLargeEnumSetSerialization() {
+ assertTrue(Element.values().length > 64);
+ String s = "aced0005737200246a6176612e7574696c2e456e756d5365742453657269616c"
+ + "697a6174696f6e50726f78790507d3db7654cad10200024c000b656c656d656e7"
+ + "4547970657400114c6a6176612f6c616e672f436c6173733b5b0008656c656d65"
+ + "6e74737400115b4c6a6176612f6c616e672f456e756d3b7870767200256c69626"
+ + "36f72652e6a6176612e7574696c2e456e756d5365745465737424456c656d656e"
+ + "7400000000000000001200007872000e6a6176612e6c616e672e456e756d00000"
+ + "000000000001200007870757200115b4c6a6176612e6c616e672e456e756d3ba8"
+ + "8dea2d33d22f980200007870000000047e71007e0004740001487e71007e00047"
+ + "4000254427e71007e000474000244597e71007e000474000355554f";
+ EnumSet<Element> set = EnumSet.of(Element.H, Element.TB, Element.DY, Element.UUO);
+ new SerializationTester<EnumSet<Element>>(set, s).test();
+ }
+
+ public void testDeserializeRemovedValue() throws Exception {
+ /*
+ * enum Roshambo {
+ * ROCK, PAPER, SCISSORS, LIZARD, SPOCK
+ * }
+ * EnumSet<Roshambo> set = EnumSet.of(Roshambo.SPOCK);
+ */
+ String s = "aced0005737200246a6176612e7574696c2e456e756d5365742453657269616c"
+ + "697a6174696f6e50726f78790507d3db7654cad10200024c000b656c656d656e7"
+ + "4547970657400114c6a6176612f6c616e672f436c6173733b5b0008656c656d65"
+ + "6e74737400115b4c6a6176612f6c616e672f456e756d3b7870767200266c69626"
+ + "36f72652e6a6176612e7574696c2e456e756d5365745465737424526f7368616d"
+ + "626f00000000000000001200007872000e6a6176612e6c616e672e456e756d000"
+ + "00000000000001200007870757200115b4c6a6176612e6c616e672e456e756d3b"
+ + "a88dea2d33d22f980200007870000000017e71007e000474000553504f434b";
+ try {
+ SerializationTester.deserializeHex(s);
+ fail();
+ } catch (InvalidObjectException expected) {
+ }
+ }
+
+ public void testDeserializeShuffledOrdinals() throws Exception {
+ /*
+ * enum Roshambo {
+ * SCISSORS, ROCK, PAPER
+ * }
+ * EnumSet<Roshambo> set = EnumSet.of(Roshambo.SCISSORS, Roshambo.ROCK)
+ */
+ String s = "aced0005737200246a6176612e7574696c2e456e756d5365742453657269616c"
+ + "697a6174696f6e50726f78790507d3db7654cad10200024c000b656c656d656e7"
+ + "4547970657400114c6a6176612f6c616e672f436c6173733b5b0008656c656d65"
+ + "6e74737400115b4c6a6176612f6c616e672f456e756d3b7870767200266c69626"
+ + "36f72652e6a6176612e7574696c2e456e756d5365745465737424526f7368616d"
+ + "626f00000000000000001200007872000e6a6176612e6c616e672e456e756d000"
+ + "00000000000001200007870757200115b4c6a6176612e6c616e672e456e756d3b"
+ + "a88dea2d33d22f980200007870000000027e71007e000474000853434953534f5"
+ + "2537e71007e0004740004524f434b";
+ assertEquals(EnumSet.of(Roshambo.ROCK, Roshambo.SCISSORS),
+ SerializationTester.deserializeHex(s));
+ }
+
+ enum Roshambo {
+ ROCK, PAPER, SCISSORS
+ }
+
+ enum Element {
+ H, HE, LI, BE, B, C, N, O, F, NE, NA, MG, AL, SI, P, S, CL, AR, K, CA, SC, TI, V, CR, MN,
+ FE, CO, NI, CU, ZN, GA, GE, AS, SE, BR, KR, RB, SR, Y, ZR, NB, MO, TC, RU, RH, PD, AG, CD,
+ IN, SN, SB, TE, I, XE, CS, BA, LA, CE, PR, ND, PM, SM, EU, GD, TB, DY, HO, ER, TM, YB, LU,
+ HF, TA, W, RE, OS, IR, PT, AU, HG, TL, PB, BI, PO, AT, RN, FR, RA, AC, TH, PA, U, NP, PU,
+ AM, CM, BK, CF, ES, FM, MD, NO, LR, RF, DB, SG, BH, HS, MT, DS, RG, CN, UUT, UUQ, UUP, UUH,
+ UUS, UUO
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/EventObjectTest.java b/luni/src/test/java/libcore/java/util/EventObjectTest.java
index a80e8c7..dc87d61 100644
--- a/luni/src/test/java/libcore/java/util/EventObjectTest.java
+++ b/luni/src/test/java/libcore/java/util/EventObjectTest.java
@@ -19,6 +19,7 @@
import java.util.EventObject;
import junit.framework.TestCase;
+import libcore.util.SerializationTester;
public final class EventObjectTest extends TestCase {
@@ -44,7 +45,7 @@
+ "c8d094e186d7da80200007870";
Object source = new Object();
EventObject eventObject = new EventObject(source);
- new SerializableTester<EventObject>(eventObject, s) {
+ new SerializationTester<EventObject>(eventObject, s) {
@Override protected boolean equals(EventObject a, EventObject b) {
return a.getSource() == null
|| b.getSource() == null
diff --git a/luni/src/test/java/libcore/java/util/OldCollectionsTest.java b/luni/src/test/java/libcore/java/util/OldCollectionsTest.java
index f54fc56..8a31ba7 100644
--- a/luni/src/test/java/libcore/java/util/OldCollectionsTest.java
+++ b/luni/src/test/java/libcore/java/util/OldCollectionsTest.java
@@ -17,8 +17,6 @@
package libcore.java.util;
-import junit.framework.TestCase;
-
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,12 +36,11 @@
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
-
+import junit.framework.TestCase;
+import libcore.util.SerializationTester;
import org.apache.harmony.testframework.serialization.SerializationTest;
import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert;
-import tests.util.SerializationTester;
-
public class OldCollectionsTest extends TestCase {
private static final SerializableAssert comparator = new SerializableAssert() {
@@ -603,44 +600,147 @@
SerializationTest.verifySelf(Collections.EMPTY_SET, comparator);
}
- public void test_checkedCollectionSerializationCompatability() throws Exception {
- Collection<String> c = Collections.emptySet();
- c = Collections.checkedCollection(c, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedCollection.golden.ser");
+ public void test_checkedCollectionSerializationCompatibility() throws Exception {
+ String s = "aced0005737200276a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b6564436f6c6c656374696f6e15e96dfd18e6cc6f0200034c00016374001"
+ + "64c6a6176612f7574696c2f436f6c6c656374696f6e3b4c000474797065740011"
+ + "4c6a6176612f6c616e672f436c6173733b5b00167a65726f4c656e677468456c6"
+ + "56d656e7441727261797400135b4c6a6176612f6c616e672f4f626a6563743b78"
+ + "707372001e6a6176612e7574696c2e436f6c6c656374696f6e7324456d7074795"
+ + "3657415f5721db403cb280200007870767200106a6176612e6c616e672e537472"
+ + "696e67a0f0a4387a3bb342020000787070";
+ assertSerialized(Collections.checkedCollection(
+ Collections.<String>emptySet(), String.class), s, false);
}
- public void test_checkedListRandomAccessSerializationCompatability() throws Exception {
- List<String> c = new ArrayList<String>();
- assertTrue(c instanceof RandomAccess);
- c = Collections.checkedList(c, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedListRandomAccess.golden.ser");
+ public void test_checkedListRandomAccessSerializationCompatibility() throws Exception {
+ String s = "aced00057372002d6a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b656452616e646f6d4163636573734c69737416bc0e55a2d7f2f10200007"
+ + "87200216a6176612e7574696c2e436f6c6c656374696f6e7324436865636b6564"
+ + "4c69737400e7ce7692c45f7c0200014c00046c6973747400104c6a6176612f757"
+ + "4696c2f4c6973743b787200276a6176612e7574696c2e436f6c6c656374696f6e"
+ + "7324436865636b6564436f6c6c656374696f6e15e96dfd18e6cc6f0200034c000"
+ + "1637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b4c0004747970"
+ + "657400114c6a6176612f6c616e672f436c6173733b5b00167a65726f4c656e677"
+ + "468456c656d656e7441727261797400135b4c6a6176612f6c616e672f4f626a65"
+ + "63743b7870737200136a6176612e7574696c2e41727261794c6973747881d21d9"
+ + "9c7619d03000149000473697a6578700000000077040000000a78767200106a61"
+ + "76612e6c616e672e537472696e67a0f0a4387a3bb34202000078707071007e0009";
+ assertSerialized(Collections.checkedList(new ArrayList<String>(), String.class), s, true);
}
- public void test_checkedListSerializationCompatability() throws Exception {
- List<String> c = new LinkedList<String>();
- assertFalse(c instanceof RandomAccess);
- c = Collections.checkedList(c, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedList.golden.ser");
+ public void test_checkedListSerializationCompatibility() throws Exception {
+ String s = "aced0005737200216a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b65644c69737400e7ce7692c45f7c0200014c00046c6973747400104c6a6"
+ + "176612f7574696c2f4c6973743b787200276a6176612e7574696c2e436f6c6c65"
+ + "6374696f6e7324436865636b6564436f6c6c656374696f6e15e96dfd18e6cc6f0"
+ + "200034c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b4c"
+ + "0004747970657400114c6a6176612f6c616e672f436c6173733b5b00167a65726"
+ + "f4c656e677468456c656d656e7441727261797400135b4c6a6176612f6c616e67"
+ + "2f4f626a6563743b7870737200146a6176612e7574696c2e4c696e6b65644c697"
+ + "3740c29535d4a608822030000787077040000000078767200106a6176612e6c61"
+ + "6e672e537472696e67a0f0a4387a3bb34202000078707071007e0008";
+ assertSerialized(Collections.checkedList(new LinkedList<String>(), String.class), s, true);
}
- public void test_checkedSetSerializationCompatability() throws Exception {
- Set<String> c = new HashSet<String>();
- assertFalse(c instanceof SortedSet);
- c = Collections.checkedSet(c, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSet.golden.ser");
+ public void test_checkedSetSerializationCompatibility() throws Exception {
+ String s = "aced0005737200206a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b656453657441249ba27ad9ffab020000787200276a6176612e7574696c2"
+ + "e436f6c6c656374696f6e7324436865636b6564436f6c6c656374696f6e15e96d"
+ + "fd18e6cc6f0200034c0001637400164c6a6176612f7574696c2f436f6c6c65637"
+ + "4696f6e3b4c0004747970657400114c6a6176612f6c616e672f436c6173733b5b"
+ + "00167a65726f4c656e677468456c656d656e7441727261797400135b4c6a61766"
+ + "12f6c616e672f4f626a6563743b7870737200116a6176612e7574696c2e486173"
+ + "68536574ba44859596b8b7340300007870770c000000103f40000000000000787"
+ + "67200106a6176612e6c616e672e537472696e67a0f0a4387a3bb3420200007870"
+ + "70";
+ assertSerialized(Collections.checkedSet(new HashSet<String>(), String.class), s, true);
}
- public void test_checkedMapSerializationCompatability() throws Exception {
- Map<String, String> c = new HashMap<String, String>();
- assertFalse(c instanceof SortedMap);
- c = Collections.checkedMap(c, String.class, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedMap.golden.ser");
+ public void test_checkedMapSerializationCompatibility() throws Exception {
+ String s = "aced0005737200206a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b65644d61704fb2bcdf0d1863680200054c00076b6579547970657400114"
+ + "c6a6176612f6c616e672f436c6173733b4c00016d74000f4c6a6176612f757469"
+ + "6c2f4d61703b4c000976616c75655479706571007e00015b00127a65726f4c656"
+ + "e6774684b657941727261797400135b4c6a6176612f6c616e672f4f626a656374"
+ + "3b5b00147a65726f4c656e67746856616c7565417272617971007e00037870767"
+ + "200106a6176612e6c616e672e537472696e67a0f0a4387a3bb342020000787073"
+ + "7200116a6176612e7574696c2e486173684d61700507dac1c31660d1030002460"
+ + "00a6c6f6164466163746f724900097468726573686f6c6478703f400000000000"
+ + "0c770800000010000000007871007e00067070";
+ assertSerialized(Collections.checkedMap(
+ new HashMap<String, String>(), String.class, String.class), s);
}
- public void test_checkedSortedSetSerializationCompatability() throws Exception {
- SortedSet<String> c = new TreeSet<String>();
- c = Collections.checkedSortedSet(c, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedSet.golden.ser");
+ public void test_checkedSortedSetSerializationCompatibility() throws Exception {
+ String s = "aced0005737200266a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b6564536f72746564536574163406ba7362eb0f0200014c0002737374001"
+ + "54c6a6176612f7574696c2f536f727465645365743b787200206a6176612e7574"
+ + "696c2e436f6c6c656374696f6e7324436865636b656453657441249ba27ad9ffa"
+ + "b020000787200276a6176612e7574696c2e436f6c6c656374696f6e7324436865"
+ + "636b6564436f6c6c656374696f6e15e96dfd18e6cc6f0200034c0001637400164"
+ + "c6a6176612f7574696c2f436f6c6c656374696f6e3b4c0004747970657400114c"
+ + "6a6176612f6c616e672f436c6173733b5b00167a65726f4c656e677468456c656"
+ + "d656e7441727261797400135b4c6a6176612f6c616e672f4f626a6563743b7870"
+ + "737200116a6176612e7574696c2e54726565536574dd98509395ed875b0300007"
+ + "8707077040000000078767200106a6176612e6c616e672e537472696e67a0f0a4"
+ + "387a3bb34202000078707071007e0009";
+ assertSerialized(Collections.checkedSortedSet(new TreeSet<String>(), String.class), s, true);
}
- public void test_checkedSortedMapSerializationCompatability() throws Exception {
- SortedMap<String, String> c = new TreeMap<String, String>();
- c = Collections.checkedSortedMap(c, String.class, String.class);
- SerializationTester.assertCompatibilityEquals(c, "/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedMap.golden.ser");
+ public void test_checkedSortedMapSerializationCompatibility() throws Exception {
+ String s = "aced0005737200266a6176612e7574696c2e436f6c6c656374696f6e73244368"
+ + "65636b6564536f727465644d617016332c973afe036e0200014c0002736d74001"
+ + "54c6a6176612f7574696c2f536f727465644d61703b787200206a6176612e7574"
+ + "696c2e436f6c6c656374696f6e7324436865636b65644d61704fb2bcdf0d18636"
+ + "80200054c00076b6579547970657400114c6a6176612f6c616e672f436c617373"
+ + "3b4c00016d74000f4c6a6176612f7574696c2f4d61703b4c000976616c7565547"
+ + "9706571007e00035b00127a65726f4c656e6774684b657941727261797400135b"
+ + "4c6a6176612f6c616e672f4f626a6563743b5b00147a65726f4c656e677468566"
+ + "16c7565417272617971007e00057870767200106a6176612e6c616e672e537472"
+ + "696e67a0f0a4387a3bb3420200007870737200116a6176612e7574696c2e54726"
+ + "5654d61700cc1f63e2d256ae60300014c000a636f6d70617261746f727400164c"
+ + "6a6176612f7574696c2f436f6d70617261746f723b78707077040000000078710"
+ + "07e0008707071007e000b";
+ assertSerialized(Collections.checkedSortedMap(
+ new TreeMap<String, String>(), String.class, String.class), s);
+ }
+
+ private void assertSerialized(Collection<?> collection, String s, final boolean definesEquals) {
+ new SerializationTester<Collection<?>>(collection, s) {
+ @SuppressWarnings("unchecked")
+ @Override protected void verify(Collection<?> deserialized) throws Exception {
+ try {
+ ((Collection) deserialized).add(Boolean.TRUE);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ }
+ @Override protected boolean equals(Collection<?> a, Collection<?> b) {
+ boolean equal = definesEquals
+ ? a.equals(b)
+ : Arrays.equals(a.toArray(), b.toArray());
+ return equal
+ && (a instanceof SortedSet == b instanceof SortedSet)
+ && (a instanceof RandomAccess == b instanceof RandomAccess);
+ }
+ }.test();
+ }
+
+ private void assertSerialized(Map<?, ?> map, String s) {
+ new SerializationTester<Map<?, ?>>(map, s) {
+ @SuppressWarnings("unchecked")
+ @Override protected void verify(Map<?, ?> deserialized) throws Exception {
+ try {
+ ((Map) deserialized).put(Boolean.TRUE, "a");
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ try {
+ ((Map) deserialized).put("a", Boolean.TRUE);
+ fail();
+ } catch (ClassCastException expected) {
+ }
+ }
+ @Override protected boolean equals(Map<?, ?> a, Map<?, ?> b) {
+ return super.equals(a, b)
+ && (a instanceof SortedMap == b instanceof SortedMap);
+ }
+ }.test();
}
public void test_checkedCollectionLjava_util_CollectionLjava_lang_Class() {
diff --git a/luni/src/test/java/libcore/java/util/OldPriorityQueueTest.java b/luni/src/test/java/libcore/java/util/OldPriorityQueueTest.java
index c2e2a03..de24cf9 100644
--- a/luni/src/test/java/libcore/java/util/OldPriorityQueueTest.java
+++ b/luni/src/test/java/libcore/java/util/OldPriorityQueueTest.java
@@ -21,12 +21,9 @@
import java.util.List;
import java.util.PriorityQueue;
import junit.framework.TestCase;
-import tests.util.SerializationTester;
+import libcore.util.SerializationTester;
public class OldPriorityQueueTest extends TestCase {
-
- private static final String SERIALIZATION_FILE_NAME = "/serialization/tests/api/java/util/PriorityQueue.golden.ser";
-
public void test_ConstructorI() {
PriorityQueue<Object> queue = new PriorityQueue<Object>(100);
assertNotNull(queue);
@@ -65,43 +62,22 @@
}
public void test_Serialization() throws Exception {
- Integer[] array = { 2, 45, 7, -12, 9, 23, 17, 1118, 10, 16, 39 };
- List<Integer> list = Arrays.asList(array);
- PriorityQueue<Integer> srcIntegerQueue = new PriorityQueue<Integer>(list);
- PriorityQueue<Integer> destIntegerQueue = SerializationTester.getDeserializedObject(srcIntegerQueue);
- Arrays.sort(array);
- for (int i = 0; i < array.length; i++) {
- assertEquals(array[i], destIntegerQueue.poll());
- }
- assertEquals(0, destIntegerQueue.size());
- }
-
- public void test_Serialization_casting() throws Exception {
- Integer[] array = { 2, 45, 7, -12, 9, 23, 17, 1118, 10, 16, 39 };
- List<Integer> list = Arrays.asList(array);
- PriorityQueue<Integer> srcIntegerQueue = new PriorityQueue<Integer>(list);
- Object dodgy = SerializationTester.getDeserializedObject((Object) srcIntegerQueue);
- PriorityQueue<String> destStringQueue = (PriorityQueue<String>) dodgy;
- // will not incur class cast exception.
- Object o = destStringQueue.peek();
- Arrays.sort(array);
- Integer I = (Integer) o;
- assertEquals(array[0], I);
- }
-
- public void test_SerializationCompatibility_cast() throws Exception {
- Integer[] array = { 2, 45, 7, -12, 9, 23, 17, 1118, 10, 16, 39 };
- List<Integer> list = Arrays.asList(array);
+ String s = "aced0005737200176a6176612e7574696c2e5072696f72697479517565756594"
+ + "da30b4fb3f82b103000249000473697a654c000a636f6d70617261746f7274001"
+ + "64c6a6176612f7574696c2f436f6d70617261746f723b78700000000b70770400"
+ + "00000c737200116a6176612e6c616e672e496e746567657212e2a0a4f78187380"
+ + "2000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac"
+ + "951d0b94e08b0200007870fffffff47371007e0003000000027371007e0003000"
+ + "000077371007e00030000000a7371007e0003000000097371007e000300000017"
+ + "7371007e0003000000117371007e00030000045e7371007e00030000002d73710"
+ + "07e0003000000107371007e00030000002778";
PriorityQueue<Integer> srcIntegerQueue = new PriorityQueue<Integer>(
- list);
- PriorityQueue<String> destStringQueue = (PriorityQueue<String>) SerializationTester
- .readObject(srcIntegerQueue, SERIALIZATION_FILE_NAME);
-
- // will not incur class cast exception.
- Object o = destStringQueue.peek();
- Arrays.sort(array);
- Integer I = (Integer) o;
- assertEquals(array[0], I);
+ Arrays.asList(2, 45, 7, -12, 9, 23, 17, 1118, 10, 16, 39));
+ new SerializationTester<PriorityQueue<Integer>>(srcIntegerQueue, s) {
+ @Override protected boolean equals(PriorityQueue<Integer> a, PriorityQueue<Integer> b) {
+ return Arrays.equals(a.toArray(), b.toArray());
+ }
+ }.test();
}
private static class MockComparatorStringByLength implements
diff --git a/luni/src/test/java/libcore/java/util/SerializableTester.java b/luni/src/test/java/libcore/java/util/SerializableTester.java
deleted file mode 100644
index 50b6435..0000000
--- a/luni/src/test/java/libcore/java/util/SerializableTester.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2010 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 libcore.java.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import static junit.framework.Assert.*;
-import junit.framework.AssertionFailedError;
-
-public class SerializableTester<T> {
-
- private final String golden;
- private final T value;
-
- public SerializableTester(T value, String golden) {
- this.golden = golden;
- this.value = value;
- }
-
- /**
- * Returns true if {@code a} and {@code b} are equal. Override this if
- * {@link Object#equals} isn't appropriate or sufficient for this tester's
- * value type.
- */
- protected boolean equals(T a, T b) {
- return a.equals(b);
- }
-
- /**
- * Verifies that {@code deserialized} is valid. Implementations of this
- * method may mutate {@code deserialized}.
- */
- protected void verify(T deserialized) {}
-
- public void test() {
- try {
- if (golden == null || golden.length() == 0) {
- fail("No golden value supplied! Consider using this: "
- + hexEncode(serialize(value)));
- }
-
- @SuppressWarnings("unchecked") // deserialize should return the proper type
- T deserialized = (T) deserialize(hexDecode(golden));
- assertTrue("User-constructed value doesn't equal deserialized golden value",
- equals(value, deserialized));
-
- @SuppressWarnings("unchecked") // deserialize should return the proper type
- T reserialized = (T) deserialize(serialize(value));
- assertTrue("User-constructed value doesn't equal itself, reserialized",
- equals(value, reserialized));
-
- // just a sanity check! if this fails, verify() is probably broken
- verify(value);
- verify(deserialized);
- verify(reserialized);
-
- } catch (Exception e) {
- Error failure = new AssertionFailedError();
- failure.initCause(e);
- throw failure;
- }
- }
-
- private static byte[] serialize(Object object) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- new ObjectOutputStream(out).writeObject(object);
- return out.toByteArray();
- }
-
- private static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
- ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
- Object result = in.readObject();
- assertEquals(-1, in.read());
- return result;
- }
-
- private static String hexEncode(byte[] bytes) {
- StringBuilder result = new StringBuilder(bytes.length * 2);
- for (byte b : bytes) {
- result.append(String.format("%02x", b));
- }
- return result.toString();
- }
-
- private static byte[] hexDecode(String s) {
- byte[] result = new byte[s.length() / 2];
- for (int i = 0; i < result.length; i++) {
- result[i] = (byte) Integer.parseInt(s.substring(i*2, i*2 + 2), 16);
- }
- return result;
- }
-
- public static String serializeHex(Object object) throws IOException {
- return hexEncode(serialize(object));
- }
-
- public static Object deserializeHex(String hex) throws IOException, ClassNotFoundException {
- return deserialize(hexDecode(hex));
- }
-}
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 9708c2a..484668b 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -149,6 +149,15 @@
assertFalse(denver.hasSameRules(phoenix));
}
+ // http://code.google.com/p/android/issues/detail?id=24036
+ public void testNullId() throws Exception {
+ try {
+ TimeZone.getTimeZone(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
// http://b.corp.google.com/issue?id=6556561
public void testCustomZoneIds() throws Exception {
// These are all okay (and equivalent).
diff --git a/luni/src/test/java/libcore/java/util/TreeMapTest.java b/luni/src/test/java/libcore/java/util/TreeMapTest.java
index 4a048f5..32fcba4 100644
--- a/luni/src/test/java/libcore/java/util/TreeMapTest.java
+++ b/luni/src/test/java/libcore/java/util/TreeMapTest.java
@@ -26,11 +26,12 @@
import java.util.SortedMap;
import java.util.TreeMap;
import junit.framework.TestCase;
+import libcore.util.SerializationTester;
public class TreeMapTest extends TestCase {
/**
- * Test that the entrySet() method produces correctly mutable Entrys.
+ * Test that the entrySet() method produces correctly mutable entries.
*/
public void testEntrySetSetValue() {
TreeMap<String, String> map = new TreeMap<String, String>();
@@ -38,7 +39,7 @@
map.put("B", "b");
map.put("C", "c");
- Iterator<Entry<String,String>> iterator = map.entrySet().iterator();
+ Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
Entry<String, String> entryA = iterator.next();
assertEquals("a", entryA.setValue("x"));
assertEquals("x", entryA.getValue());
@@ -54,8 +55,8 @@
}
/**
- * Test that the entrySet() method of a submap produces correctly mutable Entrys that
- * propagate changes to the original map.
+ * Test that the entrySet() method of a sub map produces correctly mutable
+ * entries that propagate changes to the original map.
*/
public void testSubMapEntrySetSetValue() {
TreeMap<String, String> map = new TreeMap<String, String>();
@@ -65,7 +66,7 @@
map.put("D", "d");
NavigableMap<String, String> subMap = map.subMap("A", true, "C", true);
- Iterator<Entry<String,String>> iterator = subMap.entrySet().iterator();
+ Iterator<Entry<String, String>> iterator = subMap.entrySet().iterator();
Entry<String, String> entryA = iterator.next();
assertEquals("a", entryA.setValue("x"));
assertEquals("x", entryA.getValue());
@@ -96,7 +97,7 @@
}
/**
- * Test that an Entry given by any method except entrySet() of a submap is immutable.
+ * Test that an Entry given by any method except entrySet() of a sub map is immutable.
*/
public void testExceptionsOnSubMapSetValue() {
TreeMap<String, String> map = new TreeMap<String, String>();
@@ -270,7 +271,7 @@
+ "e60300014c000a636f6d70617261746f727400164c6a6176612f7574696c2f436"
+ "f6d70617261746f723b78707077040000000078";
TreeMap<String, String> map = new TreeMap<String, String>();
- new SerializableTester<TreeMap<String, String>>(map, s).test();
+ new SerializationTester<TreeMap<String, String>>(map, s).test();
}
public void testSerializationWithComparator() {
@@ -279,18 +280,18 @@
+ "f6d70617261746f723b78707372002a6a6176612e6c616e672e537472696e6724"
+ "43617365496e73656e736974697665436f6d70617261746f7277035c7d5c50e5c"
+ "e02000078707704000000027400016171007e00057400016271007e000678";
- TreeMap<String,String> map = new TreeMap<String, String>(
+ TreeMap<String, String> map = new TreeMap<String, String>(
String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
- new SerializableTester<NavigableMap<String, String>>(map, s) {
+ new SerializationTester<NavigableMap<String, String>>(map, s) {
@Override protected void verify(NavigableMap<String, String> deserialized) {
assertEquals(0, deserialized.comparator().compare("X", "x"));
}
}.test();
}
- public void testSubmapSerialization() {
+ public void testSubMapSerialization() {
String s = "aced0005737200216a6176612e7574696c2e547265654d617024417363656e646"
+ "96e675375624d61700cab946d1f0fab1c020000787200216a6176612e7574696c2"
+ "e547265654d6170244e6176696761626c655375624d6170e2d0a70e64210e08020"
@@ -304,25 +305,25 @@
+ "97665436f6d70617261746f7277035c7d5c50e5ce0200007870770400000004710"
+ "07e000671007e00067400016271007e000c71007e000571007e000574000164710"
+ "07e000d78";
- TreeMap<String,String> map = new TreeMap<String, String>(
+ TreeMap<String, String> map = new TreeMap<String, String>(
String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
- SortedMap<String, String> submap = map.subMap("a", "c");
- new SerializableTester<SortedMap<String, String>>(submap, s) {
+ SortedMap<String, String> subMap = map.subMap("a", "c");
+ new SerializationTester<SortedMap<String, String>>(subMap, s) {
@Override protected void verify(SortedMap<String, String> deserialized) {
try {
deserialized.put("e", "e");
fail();
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException expected) {
}
}
}.test();
}
- public void testNavigableSubmapSerialization() {
+ public void testNavigableSubMapSerialization() {
String s = "aced0005737200216a6176612e7574696c2e547265654d617024417363656e646"
+ "96e675375624d61700cab946d1f0fab1c020000787200216a6176612e7574696c2"
+ "e547265654d6170244e6176696761626c655375624d6170e2d0a70e64210e08020"
@@ -336,19 +337,19 @@
+ "97665436f6d70617261746f7277035c7d5c50e5ce0200007870770400000004710"
+ "07e000671007e00067400016271007e000c71007e000571007e000574000164710"
+ "07e000d78";
- TreeMap<String,String> map = new TreeMap<String, String>(
+ TreeMap<String, String> map = new TreeMap<String, String>(
String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
- SortedMap<String, String> submap = map.subMap("a", false, "c", true);
- new SerializableTester<SortedMap<String, String>>(submap, s) {
+ SortedMap<String, String> subMap = map.subMap("a", false, "c", true);
+ new SerializationTester<SortedMap<String, String>>(subMap, s) {
@Override protected void verify(SortedMap<String, String> deserialized) {
try {
deserialized.put("e", "e");
fail();
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException expected) {
}
}
}.test();
@@ -370,12 +371,12 @@
+ "07e000b78737200286a6176612e7574696c2e436f6c6c656374696f6e732452657"
+ "665727365436f6d70617261746f7232000003fa6c354d510200014c0003636d707"
+ "1007e0001787071007e0009";
- TreeMap<String,String> map = new TreeMap<String, String>(
+ TreeMap<String, String> map = new TreeMap<String, String>(
String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
NavigableMap<String, String> descendingMap = map.descendingMap();
- new SerializableTester<NavigableMap<String, String>>(descendingMap, s) {
+ new SerializationTester<NavigableMap<String, String>>(descendingMap, s) {
@Override protected void verify(NavigableMap<String, String> deserialized) {
assertEquals("b", deserialized.navigableKeySet().first());
}
@@ -388,11 +389,11 @@
+ "f6d70617261746f723b78707372002a6a6176612e6c616e672e537472696e6724"
+ "43617365496e73656e736974697665436f6d70617261746f7277035c7d5c50e5c"
+ "e02000078707704000000027400016171007e00057400016271007e000678";
- TreeMap<String,String> map = new TreeMap<String, String>(
+ TreeMap<String, String> map = new TreeMap<String, String>(
String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
- new SerializableTester<TreeMap<String, String>>(map, s) {
+ new SerializationTester<TreeMap<String, String>>(map, s) {
@Override protected void verify(TreeMap<String, String> deserialized) {
assertEquals(0, deserialized.comparator().compare("X", "x"));
}
@@ -402,7 +403,7 @@
/**
* On JDK5, this fails with a NullPointerException after deserialization!
*/
- public void testJava5SubmapSerialization() {
+ public void testJava5SubMapSerialization() {
String s = "aced0005737200186a6176612e7574696c2e547265654d6170245375624d6170"
+ "a5818343a213c27f0200055a000966726f6d53746172745a0005746f456e644c0"
+ "00766726f6d4b65797400124c6a6176612f6c616e672f4f626a6563743b4c0006"
@@ -414,18 +415,18 @@
+ "261746f7277035c7d5c50e5ce020000787077040000000471007e000471007e00"
+ "047400016271007e000a7400016371007e000b7400016471007e000c7871007e0"
+ "00b";
- TreeMap<String,String> map = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+ TreeMap<String, String> map = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
- SortedMap<String, String> submap = map.subMap("a", "c");
- new SerializableTester<SortedMap<String, String>>(submap, s) {
+ SortedMap<String, String> subMap = map.subMap("a", "c");
+ new SerializationTester<SortedMap<String, String>>(subMap, s) {
@Override protected void verify(SortedMap<String, String> deserialized) {
try {
deserialized.put("e", "e");
fail();
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException expected) {
}
}
}.test();
diff --git a/luni/src/test/java/libcore/java/util/TreeSetTest.java b/luni/src/test/java/libcore/java/util/TreeSetTest.java
new file mode 100644
index 0000000..93b4982
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/TreeSetTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 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 libcore.java.util;
+
+import java.util.NavigableSet;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import libcore.util.SerializationTester;
+
+public final class TreeSetTest extends TestCase {
+
+ public void testEmptySetSerialization() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b03000078707077040000000078";
+ TreeSet<String> set = new TreeSet<String>();
+ new SerializationTester<TreeSet<String>>(set, s).test();
+ }
+
+ public void testSerializationWithComparator() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b03000078707372002a6a6176612e6c616e672e537472696e672443617365496"
+ + "e73656e736974697665436f6d70617261746f7277035c7d5c50e5ce0200007870"
+ + "770400000002740001617400016278";
+ TreeSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ set.add("a");
+ set.add("b");
+ new SerializationTester<NavigableSet<String>>(set, s) {
+ @Override protected void verify(NavigableSet<String> deserialized) {
+ assertEquals(0, deserialized.comparator().compare("X", "x"));
+ }
+ }.test();
+ }
+
+ public void testSubSetSerialization() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b03000078707372002a6a6176612e6c616e672e537472696e672443617365496"
+ + "e73656e736974697665436f6d70617261746f7277035c7d5c50e5ce0200007870"
+ + "770400000002740001617400016278";
+ TreeSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ set.add("a");
+ set.add("b");
+ set.add("c");
+ set.add("d");
+ final SortedSet<String> subSet = set.subSet("a", "c");
+ new SerializationTester<SortedSet<String>>(subSet, s) {
+ @Override protected void verify(SortedSet<String> deserialized) {
+ assertBounded(deserialized, deserialized == subSet);
+ }
+ }.test();
+ }
+
+ public void testNavigableSubSetSerialization() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b03000078707372002a6a6176612e6c616e672e537472696e672443617365496"
+ + "e73656e736974697665436f6d70617261746f7277035c7d5c50e5ce0200007870"
+ + "770400000002740001627400016378";
+ TreeSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ set.add("a");
+ set.add("b");
+ set.add("c");
+ set.add("d");
+ final SortedSet<String> subSet = set.subSet("a", false, "c", true);
+ new SerializationTester<SortedSet<String>>(subSet, s) {
+ @Override protected void verify(SortedSet<String> deserialized) {
+ assertBounded(deserialized, deserialized == subSet);
+ }
+ }.test();
+ }
+
+ /**
+ * Regrettably, serializing a TreeSet causes it to forget its bounds. This
+ * is unlike a serialized TreeMap which retains its bounds when serialized.
+ */
+ private void assertBounded(SortedSet<String> deserialized, boolean bounded) {
+ if (bounded) {
+ try {
+ deserialized.add("e");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ } else {
+ assertTrue(deserialized.add("e"));
+ assertTrue(deserialized.remove("e"));
+ }
+ }
+
+ /**
+ * Test that TreeSet never attempts to serialize a non-serializable
+ * comparator. http://b/5552608
+ */
+ public void testDescendingSetSerialization() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b0300007870737200276a6176612e7574696c2e436f6c6c656374696f6e73245"
+ + "2657665727365436f6d70617261746f7264048af0534e4ad00200007870770400"
+ + "000002740001627400016178";
+ TreeSet<String> set = new TreeSet<String>();
+ set.add("a");
+ set.add("b");
+ NavigableSet<String> descendingSet = set.descendingSet();
+ new SerializationTester<NavigableSet<String>>(descendingSet, s) {
+ @Override protected void verify(NavigableSet<String> deserialized) {
+ assertEquals("b", deserialized.first());
+ }
+ }.test();
+ }
+
+ public void testJava5SerializationWithComparator() {
+ String s = "aced0005737200116a6176612e7574696c2e54726565536574dd98509395ed87"
+ + "5b03000078707372002a6a6176612e6c616e672e537472696e672443617365496"
+ + "e73656e736974697665436f6d70617261746f7277035c7d5c50e5ce0200007870"
+ + "770400000002740001617400016278";
+ TreeSet<String> set = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ set.add("a");
+ set.add("b");
+ new SerializationTester<TreeSet<String>>(set, s) {
+ @Override protected void verify(TreeSet<String> deserialized) {
+ assertEquals(0, deserialized.comparator().compare("X", "x"));
+ }
+ }.test();
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/beans/PropertyChangeSupportTest.java b/luni/src/test/java/libcore/java/util/beans/PropertyChangeSupportTest.java
index 4c9d88d..3bfecc2 100644
--- a/luni/src/test/java/libcore/java/util/beans/PropertyChangeSupportTest.java
+++ b/luni/src/test/java/libcore/java/util/beans/PropertyChangeSupportTest.java
@@ -27,7 +27,7 @@
import java.util.EventListener;
import java.util.List;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public final class PropertyChangeSupportTest extends TestCase {
@@ -243,7 +243,7 @@
support.addPropertyChangeListener("a", listenerToA);
support.addPropertyChangeListener("a", listenerToA);
- new SerializableTester<PropertyChangeSupport>(support, s) {
+ new SerializationTester<PropertyChangeSupport>(support, s) {
@Override protected boolean equals(PropertyChangeSupport a, PropertyChangeSupport b) {
return describe(a.getPropertyChangeListeners())
.equals(describe(b.getPropertyChangeListeners()));
diff --git a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
index b10be33..a5ca2a2 100644
--- a/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
+++ b/luni/src/test/java/libcore/java/util/concurrent/CopyOnWriteArrayListTest.java
@@ -28,7 +28,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public final class CopyOnWriteArrayListTest extends TestCase {
@@ -265,7 +265,7 @@
List<String> contents = Arrays.asList("a", "b", "c", null, "e");
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(contents);
- new SerializableTester<CopyOnWriteArrayList<String>>(list, s).test();
+ new SerializationTester<CopyOnWriteArrayList<String>>(list, s).test();
}
/**
diff --git a/luni/src/test/java/libcore/java/util/regex/OldAndroidRegexTest.java b/luni/src/test/java/libcore/java/util/regex/OldAndroidRegexTest.java
new file mode 100644
index 0000000..9d4c22d
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/regex/OldAndroidRegexTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 libcore.java.util.regex;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import junit.framework.TestCase;
+
+public final class OldAndroidRegexTest extends TestCase {
+ public void testMatches() throws Exception {
+ /* Tests class Matcher */
+
+ Pattern p = Pattern.compile("bcd");
+ Matcher m = p.matcher("bcd");
+ assertTrue("Should match.", m.matches());
+
+ /* Pattern in the middle */
+ p = Pattern.compile("bcd");
+ m = p.matcher("abcdefg");
+ assertFalse("Should not match.", m.matches());
+
+ /* Pattern at the head */
+ m = p.matcher("bcdefg");
+ assertFalse("Should not match.", m.matches());
+
+ /* Pattern at the tail */
+ m = p.matcher("abcd");
+ assertFalse("Should not match.", m.matches());
+
+ /* Make sure matches() doesn't change after calls to find() */
+ p = Pattern.compile(".*");
+ m = p.matcher("abc");
+ assertTrue(m.matches());
+ assertTrue(m.find());
+ assertTrue(m.matches());
+
+ p = Pattern.compile(".");
+ m = p.matcher("abc");
+ assertFalse(m.matches());
+ assertTrue(m.find());
+ assertFalse(m.matches());
+
+ /* Make sure matches() agrees after a reset() */
+ m.reset("z");
+ assertTrue(m.matches());
+
+ m.reset("xyz");
+ assertFalse(m.matches());
+
+ /* Tests class Pattern */
+
+ assertFalse("Erroneously matched partial string. " +
+ "See http://b/issue?id=754601", Pattern.matches("er", "xer"));
+ assertFalse("Erroneously matched partial string. " +
+ "See http://b/issue?id=754601", Pattern.matches("xe", "xer"));
+ assertTrue("Generic regex should match.",
+ Pattern.matches(".*", "bcd"));
+ assertTrue("Grouped regex should match.",
+ Pattern.matches("(b(c(d)))", "bcd"));
+ assertTrue("Grouped regex should match.",
+ Pattern.matches("(b)(c)(d)", "bcd"));
+ }
+
+ public void testGroupCount() throws Exception {
+ Pattern p = Pattern.compile(
+ "\\b(?:\\+?1)?"
+ + "(?:[ -\\.])?"
+ + "\\(?(\\d{3})?\\)?"
+ + "(?:[ -\\.\\/])?"
+ + "(\\d{3})"
+ + "(?:[ -\\.])?"
+ + "(\\d{4})\\b"
+ );
+
+ Matcher m = p.matcher("1 (919) 555-1212");
+
+ assertEquals("groupCount is incorrect, see http://b/issue?id=759412",
+ 3, m.groupCount());
+ }
+
+ public void testGroups() throws Exception {
+ Pattern p = Pattern.compile("(b)([c|d])(z*)");
+ Matcher m = p.matcher("abcdefg");
+
+ /* Must call find() first, otherwise group*() are undefined. */
+ assertTrue(m.find());
+
+ assertEquals(3, m.groupCount());
+
+ assertEquals("bc", m.group(0));
+ assertEquals("b", m.group(1));
+ assertEquals("c", m.group(2));
+ assertEquals("", m.group(3));
+ }
+
+ public void testFind() throws Exception {
+ Pattern p = Pattern.compile(".");
+ Matcher m = p.matcher("abc");
+
+ assertTrue(m.find());
+ assertEquals("a", m.group(0));
+
+ assertTrue(m.find());
+ assertEquals("b", m.group(0));
+
+ assertTrue(m.find());
+ assertEquals("c", m.group(0));
+
+ assertFalse(m.find());
+ }
+
+ public void testReplaceAll() throws Exception {
+ // Begins with non-matching text, ends with matching text
+ Pattern p = Pattern.compile("a*b");
+ Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+ String r = m.replaceAll("-");
+ assertEquals("foo-foo-foo-foo-", r);
+
+ // Begins with matching text, ends with non-matching text
+ p = Pattern.compile("a*b");
+ m = p.matcher("aabfooaabfooabfoobfoo");
+
+ r = m.replaceAll("-");
+ assertEquals("-foo-foo-foo-foo", r);
+ }
+
+ public void testReplaceFirst() throws Exception {
+ // Begins with non-matching text, ends with matching text
+ Pattern p = Pattern.compile("a*b");
+ Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+ String r = m.replaceFirst("-");
+ assertEquals("foo-fooaabfooabfoob", r);
+
+ // Begins with matching text, ends with non-matching text
+ p = Pattern.compile("a*b");
+ m = p.matcher("aabfooaabfooabfoobfoo");
+
+ r = m.replaceFirst("-");
+ assertEquals("-fooaabfooabfoobfoo", r);
+ }
+
+ public void testSplit() throws Exception {
+ Pattern p = Pattern.compile(":");
+ String[] strings;
+
+ strings = p.split("boo:and:foo");
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ strings = p.split("boo:and:foo", 2);
+ assertEquals(2, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and:foo", strings[1]);
+
+ strings = p.split("boo:and:foo", 5);
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ strings = p.split("boo:and:foo", -2);
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ p = Pattern.compile("o");
+
+ strings = p.split("boo:and:foo");
+ assertEquals(3, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+
+ strings = p.split("boo:and:foo", 5);
+ assertEquals(5, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ assertEquals("", strings[3]);
+ assertEquals("", strings[4]);
+
+ strings = p.split("boo:and:foo", -2);
+ assertEquals(5, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ assertEquals("", strings[3]);
+ assertEquals("", strings[4]);
+
+ strings = p.split("boo:and:foo", 0);
+ assertEquals(3, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ }
+
+ // -------------------------------------------------------------------
+ // Regression test for #1172774: Bug in Regex.java
+ // Regression test for #1216887: Regular expression match is very slow
+ public static final Pattern TOP_LEVEL_DOMAIN_PATTERN = Pattern.compile(
+ "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ + "|(biz|b[abdefghijmnorstvwyz])"
+ + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+ + "|d[ejkmoz]"
+ + "|(edu|e[cegrstu])"
+ + "|f[ijkmor]"
+ + "|(gov|g[abdefghilmnpqrstuwy])"
+ + "|h[kmnrtu]"
+ + "|(info|int|i[delmnoqrst])"
+ + "|(jobs|j[emop])"
+ + "|k[eghimnrwyz]"
+ + "|l[abcikrstuvy]"
+ + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+ + "|(name|net|n[acefgilopruz])"
+ + "|(org|om)"
+ + "|(pro|p[aefghklmnrstwy])"
+ + "|qa"
+ + "|r[eouw]"
+ + "|s[abcdeghijklmnortuvyz]"
+ + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+ + "|u[agkmsyz]"
+ + "|v[aceginu]"
+ + "|w[fs]"
+ + "|y[etu]"
+ + "|z[amw])");
+
+ public static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile(
+ "[\\+a-zA-Z0-9\\.\\_\\%\\-]+\\@"
+ + "(("
+ + "[a-zA-Z0-9]\\.|"
+ + "([a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]\\.)+)"
+ + TOP_LEVEL_DOMAIN_PATTERN
+ + ")");
+
+ public void testMonsterRegexCorrectness() {
+ assertTrue(EMAIL_ADDRESS_PATTERN.matcher("a+b@gmail.com").matches());
+ }
+
+ public void testMonsterRegexPerformance() {
+ long t0 = System.currentTimeMillis();
+ Matcher m = EMAIL_ADDRESS_PATTERN.matcher("donot repeate@RC8jjjjjjjjjjjjjjj");
+ assertFalse(m.find());
+ long t1 = System.currentTimeMillis();
+ System.out.println("RegEx performance test finished, took " + (t1 - t0) + " ms.");
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/OldAndroidZipStressTest.java b/luni/src/test/java/libcore/java/util/zip/OldAndroidZipStressTest.java
new file mode 100644
index 0000000..9196dc9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/OldAndroidZipStressTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 libcore.java.util.zip;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Random;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import junit.framework.TestCase;
+
+public final class OldAndroidZipStressTest extends TestCase {
+ /**
+ * JarEntry.getCertificates() is really slow. http://b/1046174
+ */
+ public void checkJarCertificates(File file) throws Exception {
+ JarFile jarFile = new JarFile(file);
+ JarEntry je = jarFile.getJarEntry("AndroidManifest.xml");
+ byte[] readBuffer = new byte[1024];
+
+ long t0 = System.currentTimeMillis();
+
+ // We must read the stream for the JarEntry to retrieve its certificates.
+ InputStream is = jarFile.getInputStream(je);
+ while (is.read(readBuffer, 0, readBuffer.length) != -1) {
+ }
+ is.close();
+ Certificate[] certs = je != null ? je.getCertificates() : null;
+
+ long t1 = System.currentTimeMillis();
+ System.out.println("loadCertificates() took " + (t1 - t0) + " ms");
+ if (certs == null) {
+ System.out.println("We have no certificates");
+ } else {
+ System.out.println("We have " + certs.length + " certificates");
+ }
+ }
+
+ private File[] getFiles() {
+ File[] result = new File("/system/app").listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".apk");
+ }
+ });
+ return result != null ? result : new File[0];
+ }
+
+ public void testJarCertificates() throws Exception {
+ for (File file : getFiles()) {
+ checkJarCertificates(file);
+ }
+ }
+
+ // Boot-time package scan is slow. Not expected to fail. Please see log if
+ // you are interested in the results. http://b/1212257
+ public void testZipStressManifest() throws Exception {
+ long time0 = System.currentTimeMillis();
+ byte[] buffer = new byte[512];
+ for (File file : getFiles()) {
+ System.out.println("ZIP stress test processing " + file + "...");
+
+ ZipFile zip = new ZipFile(file);
+ ZipEntry entry = zip.getEntry("AndroidManifest.xml");
+ InputStream stream = zip.getInputStream(entry);
+ int j = stream.read(buffer);
+ while (j != -1) {
+ j = stream.read(buffer);
+ }
+ stream.close();
+ }
+ long time1 = System.currentTimeMillis();
+ System.out.println("ZIP stress test finished, time was " + (time1- time0) + "ms");
+ }
+
+ public void testZipStressAllFiles() throws Exception {
+ long time0 = System.currentTimeMillis();
+ byte[] buffer = new byte[512];
+ for (File file : getFiles()) {
+ System.out.println("ZIP stress test processing " + file + "...");
+ ZipFile zip = new ZipFile(file);
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ InputStream stream = zip.getInputStream(entries.nextElement());
+ int j = stream.read(buffer);
+ while (j != -1) {
+ j = stream.read(buffer);
+ }
+ stream.close();
+ }
+ }
+ long time1 = System.currentTimeMillis();
+ System.out.println("ZIP stress test finished, time was " + (time1- time0) + "ms");
+ }
+
+ private void assertEquals(byte[] a, byte[] b) {
+ assertTrue(Arrays.equals(a, b));
+ }
+
+ /**
+ * Native memory allocated by Deflater in system_server. The fix reduced
+ * some internal ZLIB buffers in size, so this test is trying to execute a
+ * lot of deflating to ensure that things are still working properly.
+ * http://b/1185084
+ */
+ public void testZipDeflateInflateStress() throws Exception {
+ final int DATA_SIZE = 16384;
+ Random random = new Random(42); // Seed makes test reproducible
+ // Outer loop selects "mode" of test.
+ for (int j = 1; j <= 2; j++) {
+ byte[] input = new byte[DATA_SIZE];
+
+ if (j == 1) {
+ // Totally random content
+ random.nextBytes(input);
+ } else {
+ // Random contents with longer repetitions
+ int pos = 0;
+ while (pos < input.length) {
+ byte what = (byte)random.nextInt(256);
+ int howMany = random.nextInt(32);
+ if (pos + howMany >= input.length) {
+ howMany = input.length - pos;
+ }
+ Arrays.fill(input, pos, pos + howMany, what);
+ pos += howMany;
+ }
+ }
+
+ // Inner loop tries all 9 compression levels.
+ for (int i = 1; i <= 9; i++) {
+ System.out.println("ZipDeflateInflateStress test (" + j + "," + i + ")...");
+ byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure...
+
+ Deflater deflater = new Deflater(i);
+ deflater.setInput(input);
+ deflater.finish();
+ deflater.deflate(zipped);
+ deflater.end();
+
+ byte[] output = new byte[DATA_SIZE];
+
+ Inflater inflater = new Inflater();
+ inflater.setInput(zipped);
+ inflater.finished();
+ inflater.inflate(output);
+ inflater.end();
+ assertEquals(input, output);
+ }
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
index 89b430f..b7a6050 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
@@ -24,6 +24,7 @@
import java.util.Enumeration;
import java.util.Random;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -49,6 +50,7 @@
while (is.read(readBuffer, 0, readBuffer.length) != -1) {}
is.close();
}
+ zipFile.close();
}
public void testInflatingStreamsRequiringZipRefill() throws IOException {
@@ -58,13 +60,14 @@
while (in.getNextEntry() != null) {
while (in.read(readBuffer, 0, readBuffer.length) != -1) {}
}
+ in.close();
}
/**
* Compresses a single random file into a .zip archive.
*/
private File createZipFile(int uncompressedSize) throws IOException {
- File result = File.createTempFile("OldZipFileTest", "zip");
+ File result = File.createTempFile("ZipFileTest", "zip");
result.deleteOnExit();
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(result));
@@ -81,5 +84,44 @@
out.closeEntry();
out.close();
return result;
- }
+ }
+
+ public void testHugeZipFile() throws IOException {
+ int expectedEntryCount = 64*1024 - 1;
+ File f = createHugeZipFile(expectedEntryCount);
+ ZipFile zipFile = new ZipFile(f);
+ int entryCount = 0;
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ ++entryCount;
+ }
+ assertEquals(expectedEntryCount, entryCount);
+ zipFile.close();
+ }
+
+ public void testZip64Support() throws IOException {
+ try {
+ createHugeZipFile(64*1024);
+ fail(); // Make this test more like testHugeZipFile when we have Zip64 support.
+ } catch (ZipException expected) {
+ }
+ }
+
+ /**
+ * Compresses the given number of empty files into a .zip archive.
+ */
+ private File createHugeZipFile(int count) throws IOException {
+ File result = File.createTempFile("ZipFileTest", "zip");
+ result.deleteOnExit();
+
+ ZipOutputStream out = new ZipOutputStream(new FileOutputStream(result));
+ for (int i = 0; i < count; ++i) {
+ ZipEntry entry = new ZipEntry(Integer.toString(i));
+ out.putNextEntry(entry);
+ out.closeEntry();
+ }
+
+ out.close();
+ return result;
+ }
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
new file mode 100644
index 0000000..7cb7792
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 libcore.javax.net.ssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.nio.charset.Charsets;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import javax.net.ssl.DefaultHostnameVerifier;
+import javax.net.ssl.DistinguishedNameParser;
+import javax.security.auth.x500.X500Principal;
+import junit.framework.TestCase;
+
+public final class DefaultHostnameVerifierTest extends TestCase {
+ private static final int ALT_UNKNOWN = 0;
+ private static final int ALT_DNS_NAME = 2;
+ private static final int ALT_IPA_NAME = 7;
+
+ private final DefaultHostnameVerifier verifier = new DefaultHostnameVerifier();
+
+ public void testGetFirstCn() {
+ assertFirstCn("", null);
+ assertFirstCn("ou=xxx", null);
+ assertFirstCn("ou=xxx,cn=xxx", "xxx");
+ assertFirstCn("ou=xxx+cn=yyy,cn=zzz+cn=abc", "yyy");
+ assertFirstCn("cn=a,cn=b", "a");
+ assertFirstCn("cn=Cc,cn=Bb,cn=Aa", "Cc");
+ assertFirstCn("cn=imap.gmail.com", "imap.gmail.com");
+ }
+
+ public void testGetFirstCnWithOid() {
+ assertFirstCn("2.5.4.3=a,ou=xxx", "a");
+ }
+
+ public void testGetFirstCnWithQuotedStrings() {
+ assertFirstCn("cn=\"\\\" a ,=<>#;\"", "\" a ,=<>#;");
+ assertFirstCn("cn=abc\\,def", "abc,def");
+ }
+
+ public void testGetFirstCnWithUtf8() {
+ assertFirstCn("cn=Lu\\C4\\8Di\\C4\\87", "\u004c\u0075\u010d\u0069\u0107");
+ }
+
+ public void testGetFirstCnWithWhitespace() {
+ assertFirstCn("ou=a, cn= a b ,o=x", "a b");
+ assertFirstCn("cn=\" a b \" ,o=x", " a b ");
+ }
+
+ private void assertFirstCn(String dn, String expected) {
+ X500Principal principal = new X500Principal(dn);
+ assertEquals("dn:" + dn, expected, new DistinguishedNameParser(principal).find("cn"));
+ }
+
+ public void testVerify() {
+ assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")));
+ assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap2.g.com")));
+ assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=sub.imap.g.com")));
+ }
+
+ /**
+ * If a subjectAltName extension of type ALT_DNS_NAME is present, that MUST
+ * be used as the identity and the CN should be ignored.
+ */
+ public void testSubjectAltNameAndCn() {
+ assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
+ assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
+ assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")));
+ }
+
+ public void testSubjectAltNameWithWildcard() {
+ assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com")));
+ }
+
+ public void testSubjectAltNameWithIpAddress() {
+ assertTrue(verifier.verify("1.2.3.4", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
+ assertFalse(verifier.verify("1.2.3.5", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
+ assertTrue(verifier.verify("192.168.100.1", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1")));
+ }
+
+ public void testUnknownSubjectAltName() {
+ // Has unknown subject alternative names
+ assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
+ assertTrue(verifier.verify("2.33.44.55", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
+ assertFalse(verifier.verify("g.com", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
+ assertFalse(verifier.verify("2.33.44.1", new StubX509Certificate("")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
+ .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
+ }
+
+ public void testWildcardMatchesWildcardSuffix() {
+ assertTrue(verifier.verifyHostName("b.c.d", "*.b.c.d"));
+ assertTrue(verifier.verifyHostName("imap.google.com", "*.imap.google.com"));
+ }
+
+ public void testWildcardMatchingSubstring() {
+ assertTrue(verifier.verifyHostName("b.c.d", "b*.c.d"));
+ assertTrue(verifier.verifyHostName("imap.google.com", "ima*.google.com"));
+ }
+
+ public void testWildcardMatchingEmptySubstring() {
+ assertTrue(verifier.verifyHostName("imap.google.com", "imap*.google.com"));
+ }
+
+ public void testWildcardMatchesChildDomain() {
+ assertFalse(verifier.verifyHostName("a.b.c.d", "*.c.d"));
+ }
+
+ public void testVerifyHostName() {
+ assertTrue(verifier.verifyHostName("a.b.c.d", "a.b.c.d"));
+ assertTrue(verifier.verifyHostName("a.b.c.d", "*.b.c.d"));
+ assertFalse(verifier.verifyHostName("a.b.c.d", "*.*.c.d"));
+ assertTrue(verifier.verifyHostName("imap.google.com", "imap.google.com"));
+ assertFalse(verifier.verifyHostName("imap2.google.com", "imap.google.com"));
+ assertTrue(verifier.verifyHostName("imap.google.com", "*.google.com"));
+ assertTrue(verifier.verifyHostName("imap2.google.com", "*.google.com"));
+ assertFalse(verifier.verifyHostName("imap.google.com", "*.googl.com"));
+ assertFalse(verifier.verifyHostName("imap2.google2.com", "*.google3.com"));
+ assertFalse(verifier.verifyHostName("imap.google.com", "a*.google.com"));
+ assertFalse(verifier.verifyHostName("imap.google.com", "ix*.google.com"));
+ assertTrue(verifier.verifyHostName("imap.google.com", "iMap.Google.Com"));
+ }
+
+ public void testSubjectOnlyCert() throws Exception {
+ // subject: C=JP, CN=www.example.com
+ // subject alt names: n/a
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIIC0TCCAbmgAwIBAgIJANCQbJPPw31SMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n"
+ + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1ODE4\n"
+ + "WhgPMjA2NDEwMTUyMDU4MThaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n"
+ + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsdUJk\n"
+ + "4KxADA3vlDHxNbyC27Ozw4yiSVzPTHUct471YmdDRW3orO2P5a5hRnUGV70gjH9X\n"
+ + "MU4oeOdWYAgXB9pxfLyr6621k1+uNrmaZtzp0ECH9twcwxNJJFDZsN7o9vt7V6Ej\n"
+ + "NN9weeqDr/aeQXo07a12vyVfR6jWO8jHB0e4aemwZNoYjNvM69fivQTse2ZoRVfj\n"
+ + "eSHhjRTX6I8ry4a31Hwt+fT1QiWWNN6o7+WOtpJAhX3eg4smhSD1svi2kOT8tdUe\n"
+ + "NS4hWlmXmumU9G4tI8PBurcLNTm7PB2lUlbn/IV18WavqKE/Uy/1WgAx+a1EJNdp\n"
+ + "i07AG1PsqaONKkf1AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAJrNsuL7fZZNC8gL\n"
+ + "BdePJ7DYW2e7mXANU3bCBe2BZqmXKQxKwibZnEsqA+yMLqcSd8uxISlyHY2tw9wT\n"
+ + "4wB9KPIttfNLbwn/rk+MbOTHpvyF60d9WhJJVUkPBl8D4VuPSl+VnlA54kU9dtZN\n"
+ + "+ZYdxYbNtSsI/Flz9SCoOV79W9GhN+uYJhv6RwyIMIHeMpZpyX1xSUVx5dZlmerQ\n"
+ + "WAUvghDH3fFRt2ZdnA4OXoKkTAaM3Pv7PUMsnah8bux6MQi0AuLMWFWOI1H34koH\n"
+ + "rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk\n"
+ + "taXDWI4=\n"
+ + "-----END CERTIFICATE-----");
+ assertTrue(verifier.verify("www.example.com", cert));
+ assertFalse(verifier.verify("www2.example.com", cert));
+ }
+
+ public void testSubjectAltOnlyCert() throws Exception {
+ // subject: C=JP (no CN)
+ // subject alt names: DNS:www.example.com
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIICvTCCAaWgAwIBAgIJALbA0TZk2YmNMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n"
+ + "BAYTAkpQMCAXDTEwMDExMjIwNTg1NFoYDzIwNjQxMDE1MjA1ODU0WjANMQswCQYD\n"
+ + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg6acVC9V4\n"
+ + "xNGoLNVLPbqBc8IvMvcsc88dF6MW3d9VagX3aeWU8c79tI/KOV/1AOakH7WYxw/w\n"
+ + "yD8aOX7+9BK1Hu0qKKKbSM+ycqaMthXd6xytrNDsIx5WiGUz8zTko0Gk3orIR7p7\n"
+ + "rPcNzB/zwtESkscqPv85aEn7S/yClNkzLfEzm3CtaYOc0tfhBMyzi/ipXzGMxUmx\n"
+ + "PvOLr3v/Oz5pZEQw7Kxlm4+tAtn7bJlHziQ1UW4WPIy+T3hySBEpODFiqZi7Ok3X\n"
+ + "Zjxdii62fgo5B2Ee7q5Amo0mUIwcQTDjJ2CLAqzYnSh3tpiPJGjEIjmRyCoMQ1bx\n"
+ + "7D+y7nSPIq8CAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0G\n"
+ + "CSqGSIb3DQEBBQUAA4IBAQBsGEh+nHc0l9FJTzWqvG3qs7i6XoJZdtThCDx4HjKJ\n"
+ + "8GMrJtreNN4JvIxn7KC+alVbnILjzCRO+c3rsnpxKBi5cp2imjuw5Kf/x2Seimb9\n"
+ + "UvZbaJvBVOzy4Q1IGef9bLy3wZzy2/WfBFyvPTAkgkRaX7LN2jnYOYVhNoNFrwqe\n"
+ + "EWxkA6fzrpyseUEFeGFFjGxRSRCDcQ25Eq6d9rkC1x21zNtt4QwZBO0wHrTy155M\n"
+ + "JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT\n"
+ + "9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj\n"
+ + "-----END CERTIFICATE-----");
+ assertTrue(verifier.verify("www.example.com", cert));
+ assertFalse(verifier.verify("www2.example.com", cert));
+ }
+
+ public void testSubjectWithAltNamesCert() throws Exception {
+ // subject: C=JP, CN=www.example.com
+ // subject alt names: DNS:www2.example.com, DNS:www3.example.com
+ // * Subject should be ignored, because it has subject alt names.
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIIDBDCCAeygAwIBAgIJALv14qjcuhw9MA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n"
+ + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1OTM4\n"
+ + "WhgPMjA2NDEwMTUyMDU5MzhaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n"
+ + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiTVgU\n"
+ + "kBO9KNYZZLmiPR0eBrk8u61CLnm35BGKW8EFpDaINLbbIFIQvqOMekURON/N+xFY\n"
+ + "D8roo7aFZVuHWAUqFcOJ4e6NmviK5qocLihtzAexsw4f4AzZxM3A8kcLlWLyAt7e\n"
+ + "EVLxhcMHogY7GaF6q+33Z8p+zp6x3tj07mwyPrriCLse2PeRsRunZl/fp/VvRlr6\n"
+ + "YbC7CbRrhnIv5nqohs8BsbBiiFpxQftsMQmiXhY2LUzqY2RXUIOw24fHjoQkHTL2\n"
+ + "4z5nUM3b6ueQe+CBnobUS6fzK/36Nct4dRpev9i/ORdRLuIDKJ+QR16G1V/BJYBR\n"
+ + "dAK+3iXvg6z8vP1XAgMBAAGjMTAvMC0GA1UdEQQmMCSCEHd3dzIuZXhhbXBsZS5j\n"
+ + "b22CEHd3dzMuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAJQNf38uXm3h\n"
+ + "0vsF+Yd6/HqM48Su7tWnTDAfTXnQZZkzjzITq3JXzquMXICktAVN2cLnT9zPfRAE\n"
+ + "8V8A3BNO5zXiR5W3o/mJP5HQ3/WxpzBGM2N+YmDCJyBoQrIVaAZaXAZUaBBvn5A+\n"
+ + "kEVfGWquwIFuvA67xegbJOCRLD4eUzRdNsn5+NFiakWO1tkFqEzqyQ0PNPviRjgu\n"
+ + "z9NxdPvd1JQOhydkucsPKJzlEBbGyL5QL/Jkot3Qy+FOeuNzgQUfAGtQgzRrsZDK\n"
+ + "hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI\n"
+ + "h5G2eVGXH/Y=\n"
+ + "-----END CERTIFICATE-----");
+ assertFalse(verifier.verify("www.example.com", cert));
+ assertTrue(verifier.verify("www2.example.com", cert));
+ assertTrue(verifier.verify("www3.example.com", cert));
+ assertFalse(verifier.verify("www4.example.com", cert));
+ }
+
+ public void testSubjectWithWildAltNamesCert() throws Exception {
+ // subject: C=JP, CN=www.example.com
+ // subject alt names: DNS:*.example2.com
+ // * Subject should be ignored, because it has subject alt names.
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIIC8DCCAdigAwIBAgIJAL/oWJ64VAdXMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n"
+ + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjEwMDAx\n"
+ + "WhgPMjA2NDEwMTUyMTAwMDFaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n"
+ + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbx1QB\n"
+ + "92iea7VybLYICA4MX4LWipYrRsgXUXQrcIQ3YLTQ9rH0VwScrHL4O4JDxgXCQnR+\n"
+ + "4VOzD42q1KXHJAqzqGUYCNPyvZEzkGCnQ4FBIUEmxZd5SNEefJVH3Z6GizYJomTh\n"
+ + "p78yDcoqymD9umxRC2cWFu8GscfFGMVyhsqLlOofu7UWOs22mkXPo43jDx+VOAoV\n"
+ + "n48YP3P57a2Eo0gcd4zVL00y62VegqBO/1LW38aTS7teiCBFc1TkNYa5I40yN9lP\n"
+ + "rB9ICHYQWyzf/7OxU9iauEK2w6DmSsQoLs9JzEhgeNZddkcc77ciSUCo2Hx0VpOJ\n"
+ + "BFyf2rbryJeAk+FDAgMBAAGjHTAbMBkGA1UdEQQSMBCCDiouZXhhbXBsZTIuY29t\n"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA2a14pRL+4laJ8sscQlucaDB/oSdb0cwhk4IkE\n"
+ + "kKl/ZKr6rKwPZ81sJRgzvI4imLbUAKt4AJHdpI9cIQUq1gw9bzil7LKwmFtFSPmC\n"
+ + "MYb1iadaYrvp7RE4yXrWCcSbU0hup9JQLHTrHLlqLtRuU48NHMvWYThBcS9Q/hQp\n"
+ + "nJ/JxYy3am99MHALWLAfuRxQXhE4C5utDmBwI2KD6A8SA30s+CnuegmkYScuSqBu\n"
+ + "Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT\n"
+ + "+ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ\n"
+ + "-----END CERTIFICATE-----");
+ assertFalse(verifier.verify("www.example.com", cert));
+ assertFalse(verifier.verify("www2.example.com", cert));
+ assertTrue(verifier.verify("www.example2.com", cert));
+ assertTrue(verifier.verify("abc.example2.com", cert));
+ assertFalse(verifier.verify("www.example3.com", cert));
+ }
+
+ public void testWildAltNameOnlyCert() throws Exception {
+ // subject: C=JP
+ // subject alt names: DNS:*.example.com
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIICuzCCAaOgAwIBAgIJAP82tgcvmAGxMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n"
+ + "BAYTAkpQMCAXDTEwMDExMjIxMDAyN1oYDzIwNjQxMDE1MjEwMDI3WjANMQswCQYD\n"
+ + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs528EQbcB1\n"
+ + "x4BwxthQBZrgDJzoO7KPV3dhGYoeP8EnRjapZm+T/sj9P/O4HvfxjnB+fsjYSdmE\n"
+ + "WWUtnFrP7wtG9DUC748Ea2PMV8WFhOG58dqBNIko5XzkHB7SxkNZD5S/0KQYMGLr\n"
+ + "rchDsDlmsEf2Qb6qiqpNEU70aSkExZJcH+B9nWdeBpsVFu7wtezwSWEc2NUa2bhW\n"
+ + "gcXQ/aafwHZ4o2PyGwy0sgS/UifqO9tEllC2tPleSNJOmYsVudv5Bz4Q0GG38BSz\n"
+ + "Pc0IcOoln0ZWpXbGr03V2vlXWCwzaFAl3I1T3O7YVqDiaSWoP+d0tHZzmw8aJLXd\n"
+ + "B+KaUUGxRPsCAwEAAaMcMBowGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTANBgkq\n"
+ + "hkiG9w0BAQUFAAOCAQEAJbVan4QgJ0cvpJnK9UWIVJNC+UbP87RC5go2fQiTnmGv\n"
+ + "prOrIuMqz1+vGcpIheLTLctJRHPoadXq0+UbQEIaU3pQbY6C4nNdfl+hcvmJeqrt\n"
+ + "kOCcvmIamO68iNvTSeszuHuu4O38PefrW2Xd0nn7bjFZrzBzHFhTudmnqNliP3ue\n"
+ + "KKQpqkUt5lCytnH8V/u/UCWdvVx5LnUa2XFGVLi3ongBIojW5fvF+yxn9ADqxdrI\n"
+ + "va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU\n"
+ + "qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ==\n"
+ + "-----END CERTIFICATE-----");
+ assertTrue(verifier.verify("www.example.com", cert));
+ assertTrue(verifier.verify("www2.example.com", cert));
+ assertFalse(verifier.verify("www.example2.com", cert));
+ }
+
+ public void testAltIpOnlyCert() throws Exception {
+ // subject: C=JP
+ // subject alt names: IP Address:192.168.10.1
+ X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n"
+ + "MIICsjCCAZqgAwIBAgIJALrC37YAXFIeMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n"
+ + "BAYTAkpQMCAXDTEwMDExMjIxMzk0NloYDzIwNjQxMDE1MjEzOTQ2WjANMQswCQYD\n"
+ + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr8s/4Abpby\n"
+ + "IYks5YCJE2nbWH7kj6XbwnRzsVP9RVC33bPoQ1M+2ZY24HqkigjQS/HEXR0s0bYh\n"
+ + "dewNUnTj1uGyGs6cYzsbu7x114vmVYqjxUo3hKjwfYiPeF6f3IE1vpLI7I2G32gq\n"
+ + "Zwm9c1/vXNHIdWQxCpFcuPA8P3YGfoApFX4pQPFplBUNAQqnjdmA68cbxxMC+1F3\n"
+ + "mX42D7iIEVwyVpah5HjyxjIZQlf3X7QBj0bCmkL+ibIHTALrkNNwNM6i4xzYLz/5\n"
+ + "14GkN9ncHY87eSOk6r53ptER6mQMhCe9qPRjSHnpWTTyj6IXTaYe+dDQw657B80w\n"
+ + "cSHL7Ed25zUCAwEAAaMTMBEwDwYDVR0RBAgwBocEwKgKATANBgkqhkiG9w0BAQUF\n"
+ + "AAOCAQEAgrwrtOWZT3fbi1AafpGaAiOBWSJqYqRhtQy0AfiZBxv1U0XaYqmZmpnq\n"
+ + "DVAqr0NkljowD28NBrxIFO5gBNum2ZOPDl2/5vjFn+IirUCJ9u9wS7zYkTCW2lQR\n"
+ + "xE7Ic3mfWv7wUbKDfjlWqP1IDHUxwkrBTAl+HnwOPiaKKk1ttwcrgS8AHlqASe03\n"
+ + "mlwnvJ+Stk54IneRaegL0L93sNAy63RZqnPCTxGz7eHcFwX8Jdr4sbxTxQqV6pIc\n"
+ + "WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik\n"
+ + "sAyifp8agkYdzaSh55fFmKXlFnRsQw==\n"
+ + "-----END CERTIFICATE-----");
+ assertTrue(verifier.verify("192.168.10.1", cert));
+ assertFalse(verifier.verify("192.168.10.2", cert));
+ }
+
+ X509Certificate parseCertificate(String encoded) throws Exception {
+ InputStream in = new ByteArrayInputStream(encoded.getBytes(Charsets.US_ASCII));
+ return (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(in);
+ }
+
+ private static class StubX509Certificate extends X509Certificate {
+ private final X500Principal subjectX500Principal;
+ private Collection<List<?>> subjectAlternativeNames;
+
+ public StubX509Certificate(String subjectDn) {
+ subjectX500Principal = new X500Principal(subjectDn);
+ subjectAlternativeNames = null;
+ }
+
+ public StubX509Certificate addSubjectAlternativeName(int type, String name) {
+ if (subjectAlternativeNames == null) {
+ subjectAlternativeNames = new ArrayList<List<?>>();
+ }
+ LinkedList<Object> entry = new LinkedList<Object>();
+ entry.add(type);
+ entry.add(name);
+ subjectAlternativeNames.add(entry);
+ return this;
+ }
+
+ @Override public Collection<List<?>> getSubjectAlternativeNames() {
+ return subjectAlternativeNames;
+ }
+
+ @Override public X500Principal getSubjectX500Principal() {
+ return subjectX500Principal;
+ }
+
+ @Override public void checkValidity() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void checkValidity(Date date) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int getBasicConstraints() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Principal getIssuerDN() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean[] getIssuerUniqueID() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean[] getKeyUsage() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Date getNotAfter() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Date getNotBefore() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public BigInteger getSerialNumber() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String getSigAlgName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String getSigAlgOID() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public byte[] getSigAlgParams() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public byte[] getSignature() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Principal getSubjectDN() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean[] getSubjectUniqueID() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public byte[] getTBSCertificate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int getVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public byte[] getEncoded() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public PublicKey getPublicKey() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void verify(PublicKey key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void verify(PublicKey key, String sigProvider) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Set<String> getCriticalExtensionOIDs() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public byte[] getExtensionValue(String oid) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Set<String> getNonCriticalExtensionOIDs() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean hasUnsupportedCriticalExtension() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index 5e91dc1..e3ae16f 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -166,7 +166,8 @@
TestSSLContext c = TestSSLContext.create();
SSLEngine e = c.clientContext.createSSLEngine();
String[] protocols = e.getSupportedProtocols();
- StandardNames.assertSupportedProtocols(StandardNames.SSL_SOCKET_PROTOCOLS, protocols);
+ StandardNames.assertSupportedProtocols(StandardNames.SSL_SOCKET_PROTOCOLS_SSLENGINE,
+ protocols);
assertNotSame(protocols, e.getSupportedProtocols());
c.close();
}
diff --git a/luni/src/test/java/libcore/javax/security/auth/x500/GeneralNameTest.java b/luni/src/test/java/libcore/javax/security/auth/x500/GeneralNameTest.java
new file mode 100644
index 0000000..aac5e84
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/security/auth/x500/GeneralNameTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 libcore.javax.security.auth.x500;
+
+import org.apache.harmony.security.x509.GeneralName;
+import junit.framework.TestCase;
+
+public final class GeneralNameTest extends TestCase {
+ // http://code.google.com/p/android/issues/detail?id=21311
+ public void testWildcardsInDnsName() throws Exception {
+ // examples of potential DNS wildcard locations from RFC 6125 section 7.2
+ new GeneralName(GeneralName.DNS_NAME, "*.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "fo*.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "f*o.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "*oo.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "www.*.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "www.foo*.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "*.co.uk");
+ new GeneralName(GeneralName.DNS_NAME, "*.com");
+ new GeneralName(GeneralName.DNS_NAME, "f*b*r.example.com");
+ new GeneralName(GeneralName.DNS_NAME, "*.*.example.com");
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
index 2687a82..e37ed1f 100644
--- a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
+++ b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
@@ -21,7 +21,7 @@
import java.security.cert.X509Certificate;
import javax.security.auth.x500.X500Principal;
import junit.framework.TestCase;
-import libcore.java.util.SerializableTester;
+import libcore.util.SerializationTester;
public class X500PrincipalTest extends TestCase {
@@ -37,7 +37,7 @@
+ "L=Mountain View, "
+ "O=Google Inc, "
+ "CN=www.google.com");
- new SerializableTester<X500Principal>(actual, expected).test();
+ new SerializationTester<X500Principal>(actual, expected).test();
}
/**
diff --git a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
index a62a00e..360ca44 100644
--- a/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
+++ b/luni/src/test/java/libcore/net/http/HttpResponseCacheTest.java
@@ -155,12 +155,18 @@
private void assertCached(boolean shouldPut, int responseCode) throws Exception {
server = new MockWebServer();
- server.enqueue(new MockResponse()
+ MockResponse response = new MockResponse()
.addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
.addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
.setResponseCode(responseCode)
.setBody("ABCDE")
- .addHeader("WWW-Authenticate: challenge"));
+ .addHeader("WWW-Authenticate: challenge");
+ if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) {
+ response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\"");
+ } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ response.addHeader("WWW-Authenticate: Basic realm=\"protected area\"");
+ }
+ server.enqueue(response);
server.play();
URL url = server.getUrl("/");
@@ -1503,12 +1509,12 @@
public void testCachePlusCookies() throws Exception {
server.enqueue(new MockResponse()
- .addHeader("Set-Cookie: a=FIRST; domain=.local;")
+ .addHeader("Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";")
.addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
.addHeader("Cache-Control: max-age=0")
.setBody("A"));
server.enqueue(new MockResponse()
- .addHeader("Set-Cookie: a=SECOND; domain=.local;")
+ .addHeader("Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";")
.setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
server.play();
@@ -1613,6 +1619,37 @@
.addHeader("Cache-Control: max-age=60"));
}
+ public void testConditionalHitUpdatesCache() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS))
+ .addHeader("Cache-Control: max-age=0")
+ .setBody("A"));
+ server.enqueue(new MockResponse()
+ .addHeader("Cache-Control: max-age=30")
+ .addHeader("Allow: GET, HEAD")
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.enqueue(new MockResponse().setBody("B"));
+ server.play();
+
+ // cache miss; seed the cache
+ HttpURLConnection connection1 = (HttpURLConnection) server.getUrl("/a").openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals(null, connection1.getHeaderField("Allow"));
+
+ // conditional cache hit; update the cache
+ HttpURLConnection connection2 = (HttpURLConnection) server.getUrl("/a").openConnection();
+ assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode());
+ assertEquals("A", readAscii(connection2));
+ assertEquals("GET, HEAD", connection2.getHeaderField("Allow"));
+
+ // full cache hit
+ HttpURLConnection connection3 = (HttpURLConnection) server.getUrl("/a").openConnection();
+ assertEquals("A", readAscii(connection3));
+ assertEquals("GET, HEAD", connection3.getHeaderField("Allow"));
+
+ assertEquals(2, server.getRequestCount());
+ }
+
/**
* @param delta the offset from the current date to use. Negative
* values yield dates in the past; positive values yield dates in the
@@ -1678,22 +1715,34 @@
*/
private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception {
// scenario 1: condition succeeds
- server.enqueue(response.setBody("A"));
+ server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK"));
server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
// scenario 2: condition fails
- server.enqueue(response.setBody("B"));
- server.enqueue(new MockResponse().setBody("C"));
+ server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK"));
+ server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C"));
server.play();
URL valid = server.getUrl("/valid");
- assertEquals("A", readAscii(valid.openConnection()));
- assertEquals("A", readAscii(valid.openConnection()));
+ HttpURLConnection connection1 = (HttpURLConnection) valid.openConnection();
+ assertEquals("A", readAscii(connection1));
+ assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode());
+ assertEquals("A-OK", connection1.getResponseMessage());
+ HttpURLConnection connection2 = (HttpURLConnection) valid.openConnection();
+ assertEquals("A", readAscii(connection2));
+ assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode());
+ assertEquals("A-OK", connection2.getResponseMessage());
URL invalid = server.getUrl("/invalid");
- assertEquals("B", readAscii(invalid.openConnection()));
- assertEquals("C", readAscii(invalid.openConnection()));
+ HttpURLConnection connection3 = (HttpURLConnection) invalid.openConnection();
+ assertEquals("B", readAscii(connection3));
+ assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode());
+ assertEquals("B-OK", connection3.getResponseMessage());
+ HttpURLConnection connection4 = (HttpURLConnection) invalid.openConnection();
+ assertEquals("C", readAscii(connection4));
+ assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode());
+ assertEquals("C-OK", connection4.getResponseMessage());
server.takeRequest(); // regular get
return server.takeRequest(); // conditional get
diff --git a/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java b/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
index 0db2d4d..d7ba441 100644
--- a/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
+++ b/luni/src/test/java/libcore/net/http/ParsedHeadersTest.java
@@ -17,6 +17,8 @@
package libcore.net.http;
import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import junit.framework.TestCase;
@@ -184,4 +186,59 @@
RequestHeaders parsedHeaders = new RequestHeaders(uri, headers);
assertEquals(0, parsedHeaders.getMaxAgeSeconds());
}
+
+ public void testParseChallengesWithCommaInRealm() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "s1 realm=\"ab,cd\", s2 realm=\"ef,gh\"");
+ assertEquals(Arrays.asList(new Challenge("s1", "ab,cd"), new Challenge("s2", "ef,gh")),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ public void testParseChallengesWithMultipleHeaders() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "s1 realm=\"abc\"");
+ headers.add("WWW-Authenticate", "s2 realm=\"def\"");
+ assertEquals(Arrays.asList(new Challenge("s1", "abc"), new Challenge("s2", "def")),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ public void testParseChallengesWithExtraWhitespace() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", " s1 realm=\"a\" , s2 realm=\"b\", ");
+ assertEquals(Arrays.asList(new Challenge("s1", "a"), new Challenge("s2", "b")),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ public void testParseChallengesWithMissingRealm() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "Basic");
+ assertEquals(Collections.<Challenge>emptyList(),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ public void testParseChallengesWithEmptyRealm() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "Basic realm=\"\"");
+ assertEquals(Arrays.asList(new Challenge("Basic", "")),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ public void testParseChallengesWithMissingScheme() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "realm=\"a\"");
+ assertEquals(Collections.<Challenge>emptyList(),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=11140
+ public void testParseChallengesWithManyParameters() {
+ RawHeaders headers = new RawHeaders();
+ headers.add("WWW-Authenticate", "Digest realm=\"abc\","
+ + " qop=\"auth,auth-int\","
+ + " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
+ + " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\","
+ + " Basic realm=\"def\"");
+ assertEquals(Arrays.asList(new Challenge("Digest", "abc"), new Challenge("Basic", "def")),
+ HeaderParser.parseChallenges(headers, "WWW-Authenticate"));
+ }
}
diff --git a/luni/src/test/java/libcore/xml/DeclarationTest.java b/luni/src/test/java/libcore/xml/DeclarationTest.java
index 24cb32c..4cd049f 100644
--- a/luni/src/test/java/libcore/xml/DeclarationTest.java
+++ b/luni/src/test/java/libcore/xml/DeclarationTest.java
@@ -16,7 +16,6 @@
package libcore.xml;
-import dalvik.annotation.KnownFailure;
import junit.framework.TestCase;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
@@ -79,21 +78,18 @@
assertEquals("ISO-8859-1", documentB.getInputEncoding());
}
- @KnownFailure("Dalvik doesn't parse the XML declaration")
public void testGetXmlEncoding() throws Exception {
String message = "This implementation doesn't parse the encoding from the XML declaration";
assertEquals(message, "ISO-8859-1", documentA.getXmlEncoding());
assertEquals(message, "US-ASCII", documentB.getXmlEncoding());
}
- @KnownFailure("Dalvik doesn't parse the XML declaration")
public void testGetXmlVersion() throws Exception {
String message = "This implementation doesn't parse the version from the XML declaration";
assertEquals(message, "1.0", documentA.getXmlVersion());
assertEquals(message, "1.1", documentB.getXmlVersion());
}
- @KnownFailure("Dalvik doesn't parse the XML declaration")
public void testGetXmlStandalone() throws Exception {
String message = "This implementation doesn't parse standalone from the XML declaration";
assertEquals(message, false, documentA.getXmlStandalone());
diff --git a/luni/src/test/java/libcore/xml/DomTest.java b/luni/src/test/java/libcore/xml/DomTest.java
index 79440f5..88da565 100644
--- a/luni/src/test/java/libcore/xml/DomTest.java
+++ b/luni/src/test/java/libcore/xml/DomTest.java
@@ -16,7 +16,6 @@
package libcore.xml;
-import dalvik.annotation.KnownFailure;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
@@ -186,7 +185,6 @@
* Android's parsed DOM doesn't include entity declarations. These nodes will
* only be tested for implementations that support them.
*/
- @KnownFailure("Dalvik doesn't parse entity declarations")
public void testEntityDeclarations() {
assertNotNull("This implementation does not parse entity declarations", sp);
}
@@ -195,7 +193,6 @@
* Android's parsed DOM doesn't include notations. These nodes will only be
* tested for implementations that support them.
*/
- @KnownFailure("Dalvik doesn't parse notations")
public void testNotations() {
assertNotNull("This implementation does not parse notations", png);
}
@@ -555,12 +552,10 @@
assertNoFeature("XMLVersion", "2.0");
}
- @KnownFailure("Dalvik doesn't support load/save")
public void testLoadSaveFeature() {
assertFeature("LS", "3.0");
}
- @KnownFailure("Dalvik doesn't support the element traversal feature")
public void testElementTraversalFeature() {
assertFeature("ElementTraversal", "1.0");
}
@@ -657,7 +652,6 @@
assertFalse(text.isElementContentWhitespace());
}
- @KnownFailure("Dalvik doesn't recognize element content whitespace")
public void testIsElementContentWhitespaceWithDeclaration() throws Exception {
String xml = "<!DOCTYPE menu [\n"
+ " <!ELEMENT menu (item)*>\n"
@@ -691,7 +685,6 @@
assertEquals("60%", vitamincText.getWholeText());
}
- @KnownFailure("Dalvik doesn't resolve entity references")
public void testGetWholeTextWithEntityReference() {
EntityReference spReference = document.createEntityReference("sp");
description.insertBefore(spReference, descriptionText2);
@@ -1241,7 +1234,6 @@
assertNull(document.getElementById("g"));
}
- @KnownFailure("Dalvik treats id attributes as identifiers")
public void testAttributeNamedIdIsNotAnIdByDefault() {
String message = "This implementation incorrectly interprets the "
+ "\"id\" attribute as an identifier by default.";
@@ -1385,7 +1377,6 @@
1, document.getChildNodes().getLength());
}
- @KnownFailure("Dalvik document nodes accept arbitrary child nodes")
public void testDocumentAddChild()
throws IOException, SAXException {
try {
diff --git a/luni/src/test/java/libcore/xml/NormalizeTest.java b/luni/src/test/java/libcore/xml/NormalizeTest.java
index 5e539f7..59a529d 100644
--- a/luni/src/test/java/libcore/xml/NormalizeTest.java
+++ b/luni/src/test/java/libcore/xml/NormalizeTest.java
@@ -16,7 +16,6 @@
package libcore.xml;
-import dalvik.annotation.KnownFailure;
import junit.framework.TestCase;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
@@ -205,7 +204,6 @@
* This fails under the RI because setParameter() succeeds even though
* canSetParameter() returns false.
*/
- @KnownFailure("Dalvik doesn't honor the schema-type parameter")
public void testSchemaTypeDtd() {
assertUnsupported("schema-type", "http://www.w3.org/TR/REC-xml"); // supported in RI v6
}
diff --git a/luni/src/test/java/libcore/xml/PullParserTest.java b/luni/src/test/java/libcore/xml/PullParserTest.java
index fa00fe5..71125aa 100644
--- a/luni/src/test/java/libcore/xml/PullParserTest.java
+++ b/luni/src/test/java/libcore/xml/PullParserTest.java
@@ -720,6 +720,28 @@
assertParseFailure("\ufeff<?xml version='1.0'?><input/>");
}
+ // http://code.google.com/p/android/issues/detail?id=21425
+ public void testNextTextAdvancesToEndTag() throws Exception {
+ XmlPullParser parser = newPullParser();
+ parser.setInput(new StringReader("<foo>bar</foo>"));
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("bar", parser.nextText());
+ assertEquals(XmlPullParser.END_TAG, parser.getEventType());
+ }
+
+ public void testNextTag() throws Exception {
+ XmlPullParser parser = newPullParser();
+ parser.setInput(new StringReader("<foo> <bar></bar> </foo>"));
+ assertEquals(XmlPullParser.START_TAG, parser.nextTag());
+ assertEquals("foo", parser.getName());
+ assertEquals(XmlPullParser.START_TAG, parser.nextTag());
+ assertEquals("bar", parser.getName());
+ assertEquals(XmlPullParser.END_TAG, parser.nextTag());
+ assertEquals("bar", parser.getName());
+ assertEquals(XmlPullParser.END_TAG, parser.nextTag());
+ assertEquals("foo", parser.getName());
+ }
+
private void assertParseFailure(String xml) throws Exception {
XmlPullParser parser = newPullParser();
parser.setInput(new StringReader(xml));
diff --git a/luni/src/test/java/libcore/xml/SaxTest.java b/luni/src/test/java/libcore/xml/SaxTest.java
index 108104d..721809a 100644
--- a/luni/src/test/java/libcore/xml/SaxTest.java
+++ b/luni/src/test/java/libcore/xml/SaxTest.java
@@ -16,7 +16,6 @@
package libcore.xml;
-import dalvik.annotation.KnownFailure;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
@@ -96,7 +95,6 @@
* Android's Expat-based SAX parser fails this test because Expat doesn't
* supply us with our much desired {@code xmlns="http://..."} attributes.
*/
- @KnownFailure("No xmlns attributes from Expat")
public void testYesPrefixesYesNamespaces() throws Exception {
parse(true, true, "<foo bar=\"baz\"/>", new DefaultHandler() {
@Override public void startElement(String uri, String localName,
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
index 2911192..c8df4ab 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
@@ -21,11 +21,8 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
-import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
+import java.security.KeyStore.PrivateKeyEntry;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -43,8 +40,8 @@
import junit.framework.TestCase;
import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
-import org.apache.harmony.xnet.provider.jsse.CipherSuite;
import org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSLHandshakeCallbacks;
+import static org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH;
public class NativeCryptoTest extends TestCase {
@@ -153,6 +150,28 @@
NativeCrypto.SSL_CTX_free(NativeCrypto.SSL_CTX_new());
}
+ public void test_SSL_CTX_set_session_id_context() throws Exception {
+ byte[] empty = new byte[0];
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(NULL, empty);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ int c = NativeCrypto.SSL_CTX_new();
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ NativeCrypto.SSL_CTX_set_session_id_context(c, empty);
+ NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[32]);
+ try {
+ NativeCrypto.SSL_CTX_set_session_id_context(c, new byte[33]);
+ } catch (IllegalArgumentException expected) {
+ }
+ NativeCrypto.SSL_CTX_free(c);
+ }
+
public void test_SSL_new() throws Exception {
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
@@ -161,6 +180,8 @@
assertTrue((NativeCrypto.SSL_get_options(s) & 0x01000000L) != 0); // SSL_OP_NO_SSLv2
assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_SSLv3) == 0);
assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1) == 0);
+ assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_1) == 0);
+ assertTrue((NativeCrypto.SSL_get_options(s) & NativeCrypto.SSL_OP_NO_TLSv1_2) == 0);
int s2 = NativeCrypto.SSL_new(c);
assertTrue(s != s2);
@@ -290,7 +311,7 @@
NativeCrypto.SSL_CTX_free(c);
}
- public void test_SSL_set_mode() throws Exception {
+ public void test_SSL_set_mode_and_clear_mode() throws Exception {
try {
NativeCrypto.SSL_set_mode(NULL, 0);
fail();
@@ -299,38 +320,17 @@
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
- // check SSL_MODE_HANDSHAKE_CUTTHROUGH on
- assertTrue((NativeCrypto.SSL_get_mode(s)
- & NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0);
- // clear SSL_MODE_HANDSHAKE_CUTTHROUGH off
- NativeCrypto.SSL_clear_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
- assertTrue((NativeCrypto.SSL_get_mode(s)
- & NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0);
+ // check SSL_MODE_HANDSHAKE_CUTTHROUGH off by default
+ assertEquals(0, NativeCrypto.SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
// set SSL_MODE_HANDSHAKE_CUTTHROUGH on
- NativeCrypto.SSL_set_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
+ NativeCrypto.SSL_set_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
assertTrue((NativeCrypto.SSL_get_mode(s)
- & NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0);
-
- NativeCrypto.SSL_free(s);
- NativeCrypto.SSL_CTX_free(c);
- }
-
- public void test_SSL_clear_mode() throws Exception {
- try {
- NativeCrypto.SSL_clear_mode(NULL, 0);
- fail();
- } catch (NullPointerException expected) {
- }
-
- int c = NativeCrypto.SSL_CTX_new();
- int s = NativeCrypto.SSL_new(c);
- // check SSL_MODE_HANDSHAKE_CUTTHROUGH on
- assertTrue((NativeCrypto.SSL_get_mode(s)
- & NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0);
+ & SSL_MODE_HANDSHAKE_CUTTHROUGH) != 0);
// clear SSL_MODE_HANDSHAKE_CUTTHROUGH off
- NativeCrypto.SSL_clear_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
+ NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
assertTrue((NativeCrypto.SSL_get_mode(s)
- & NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0);
+ & SSL_MODE_HANDSHAKE_CUTTHROUGH) == 0);
+
NativeCrypto.SSL_free(s);
NativeCrypto.SSL_CTX_free(c);
}
@@ -516,7 +516,6 @@
this.asn1DerEncodedCertificateChain = asn1DerEncodedCertificateChain;
this.authMethod = authMethod;
this.verifyCertificateChainCalled = true;
- return;
}
public byte[] keyTypes;
@@ -546,7 +545,6 @@
+ " handshakeCompleted");
}
this.handshakeCompletedCalled = true;
- return;
}
}
@@ -575,11 +573,10 @@
}
public static Future<TestSSLHandshakeCallbacks> handshake(final ServerSocket listener,
- final int timeout,
- final boolean client,
- final Hooks hooks) {
+ final int timeout, final boolean client, final Hooks hooks, final byte[] npnProtocols) {
ExecutorService executor = Executors.newSingleThreadExecutor();
- Future future = executor.submit(new Callable<TestSSLHandshakeCallbacks>() {
+ Future<TestSSLHandshakeCallbacks> future = executor.submit(
+ new Callable<TestSSLHandshakeCallbacks>() {
public TestSSLHandshakeCallbacks call() throws Exception {
Socket socket = (client
? new Socket(listener.getInetAddress(),
@@ -601,11 +598,8 @@
+ " timeout=" + timeout
+ " client=" + client);
}
- int session = NativeCrypto.SSL_do_handshake(s,
- fd,
- callback,
- timeout,
- client);
+ int session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client,
+ npnProtocols);
if (DEBUG) {
System.out.println("ssl=0x" + Integer.toString(s, 16)
+ " handshake"
@@ -621,7 +615,7 @@
public void test_SSL_do_handshake_NULL_SSL() throws Exception {
try {
- NativeCrypto.SSL_do_handshake(NULL, null, null, 0, false);
+ NativeCrypto.SSL_do_handshake(NULL, null, null, 0, false, null);
fail();
} catch (NullPointerException expected) {
}
@@ -632,15 +626,15 @@
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_do_handshake(s, null, null, 0, true);
+ NativeCrypto.SSL_do_handshake(s, null, null, 0, true, null);
fail();
- } catch (NullPointerException e) {
+ } catch (NullPointerException expected) {
}
try {
- NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0, true);
+ NativeCrypto.SSL_do_handshake(s, INVALID_FD, null, 0, true, null);
fail();
- } catch (NullPointerException e) {
+ } catch (NullPointerException expected) {
}
NativeCrypto.SSL_free(s);
@@ -650,17 +644,10 @@
public void test_SSL_do_handshake_normal() throws Exception {
// normal client and server case
final ServerSocket listener = new ServerSocket(0);
- Hooks cHooks = new Hooks() {
- @Override
- public int beforeHandshake(int context) throws SSLException {
- int s = super.beforeHandshake(context);
- NativeCrypto.SSL_clear_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
- return s;
- }
- };
+ Hooks cHooks = new Hooks();
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
assertTrue(clientCallback.verifyCertificateChainCalled);
@@ -680,12 +667,6 @@
Hooks cHooks = new Hooks() {
@Override
- public int beforeHandshake(int context) throws SSLException {
- int s = super.beforeHandshake(context);
- NativeCrypto.SSL_clear_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
- return s;
- }
- @Override
public void clientCertificateRequested(int s) {
super.clientCertificateRequested(s);
NativeCrypto.SSL_use_PrivateKey(s, getClientPrivateKey());
@@ -701,8 +682,8 @@
return s;
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
TestSSLHandshakeCallbacks clientCallback = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
TestSSLHandshakeCallbacks serverCallback = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
assertTrue(clientCallback.verifyCertificateChainCalled);
@@ -711,7 +692,7 @@
assertEquals("RSA", clientCallback.authMethod);
assertTrue(serverCallback.verifyCertificateChainCalled);
assertEqualCertificateChains(getClientCertificates(),
- serverCallback.asn1DerEncodedCertificateChain);
+ serverCallback.asn1DerEncodedCertificateChain);
assertEquals("RSA", serverCallback.authMethod);
assertTrue(clientCallback.clientCertificateRequestedCalled);
@@ -746,8 +727,8 @@
return s;
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -772,7 +753,7 @@
@Override
public int beforeHandshake(int context) throws SSLException {
int s = super.beforeHandshake(context);
- NativeCrypto.SSL_clear_mode(s, NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
+ NativeCrypto.SSL_clear_mode(s, SSL_MODE_HANDSHAKE_CUTTHROUGH);
return s;
}
@Override
@@ -797,13 +778,15 @@
SSLHandshakeCallbacks callback)
throws Exception {
NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER);
+ NativeCrypto.SSL_set_options(
+ s, NativeCrypto.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
NativeCrypto.SSL_renegotiate(s);
NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
try {
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -820,8 +803,8 @@
try {
Hooks cHooks = new Hooks();
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 1, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, -1, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 1, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, -1, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -835,8 +818,8 @@
try {
Hooks cHooks = new Hooks();
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, -1, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 1, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, -1, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 1, false, sHooks, null);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -894,8 +877,10 @@
serverSession[0] = session;
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client
+ = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server
+ = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -935,8 +920,10 @@
super.afterHandshake(NULL, s, NULL, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client
+ = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server
+ = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -976,8 +963,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -995,8 +982,8 @@
return s;
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -1063,8 +1050,58 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
+ client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ }
+
+ public void test_SSL_NpnNegotiateSuccess() throws Exception {
+ final byte[] clientNpnProtocols = new byte[] {
+ 8, 'h', 't', 't', 'p', '/', '1', '.', '1',
+ 3, 'f', 'o', 'o',
+ 6, 's', 'p', 'd', 'y', '/', '2',
+ };
+ final byte[] serverNpnProtocols = new byte[] {
+ 6, 's', 'p', 'd', 'y', '/', '2',
+ 3, 'f', 'o', 'o',
+ 3, 'b', 'a', 'r',
+ };
+
+ Hooks cHooks = new Hooks() {
+ @Override public int beforeHandshake(int context) throws SSLException {
+ NativeCrypto.SSL_CTX_enable_npn(context);
+ return super.beforeHandshake(context);
+ }
+ @Override public void afterHandshake(int session, int ssl, int context, Socket socket,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl);
+ assertEquals("spdy/2", new String(negotiated));
+ assertTrue("NPN should enable cutthrough on the client",
+ 0 != (NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH));
+ super.afterHandshake(session, ssl, context, socket, fd, callback);
+ }
+ };
+ Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()) {
+ @Override public int beforeHandshake(int context) throws SSLException {
+ NativeCrypto.SSL_CTX_enable_npn(context);
+ return super.beforeHandshake(context);
+ }
+ @Override public void afterHandshake(int session, int ssl, int c, Socket sock,
+ FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception {
+ byte[] negotiated = NativeCrypto.SSL_get_npn_negotiated_protocol(ssl);
+ assertEquals("spdy/2", new String(negotiated));
+ assertEquals("NPN should not enable cutthrough on the server",
+ 0, NativeCrypto.SSL_get_mode(ssl) & SSL_MODE_HANDSHAKE_CUTTHROUGH);
+ super.afterHandshake(session, ssl, c, sock, fd, callback);
+ }
+ };
+
+ ServerSocket listener = new ServerSocket(0);
+ Future<TestSSLHandshakeCallbacks> client
+ = handshake(listener, 0, true, cHooks, clientNpnProtocols);
+ Future<TestSSLHandshakeCallbacks> server
+ = handshake(listener, 0, false, sHooks, serverNpnProtocols);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1117,8 +1154,8 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1153,8 +1190,8 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1180,8 +1217,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1284,8 +1321,8 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1312,8 +1349,8 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
fail();
} catch (ExecutionException expected) {
@@ -1427,8 +1464,8 @@
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1501,8 +1538,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1530,8 +1567,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1558,8 +1595,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1585,8 +1622,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1622,8 +1659,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1655,8 +1692,8 @@
return s;
}
};
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1696,8 +1733,8 @@
}
};
Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates());
- Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks);
- Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks);
+ Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null);
+ Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null);
client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
@@ -1723,4 +1760,15 @@
assertEquals(-1372642656, NativeCrypto.X509_NAME_hash(name)); // SHA1
assertEquals(-1626170662, NativeCrypto.X509_NAME_hash_old(name)); // MD5
}
+
+ public void test_ENGINE_by_id_Failure() throws Exception {
+ NativeCrypto.ENGINE_load_dynamic();
+
+ try {
+ int engine = NativeCrypto.ENGINE_by_id("non-existent");
+ fail("Shouldn't load non-existent engine");
+ } catch (RuntimeException e) {
+ // Success
+ }
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureTest.java
new file mode 100644
index 0000000..76e423c
--- /dev/null
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSignatureTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.security.NoSuchAlgorithmException;
+import junit.framework.TestCase;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
+
+public class OpenSSLSignatureTest extends TestCase {
+
+ public void test_getInstance() throws Exception {
+ try {
+ OpenSSLSignature.getInstance("SHA1WITHDSA");
+ OpenSSLSignature.getInstance("MD5WITHRSAENCRYPTION");
+ OpenSSLSignature.getInstance("SHA1WITHRSAENCRYPTION");
+ OpenSSLSignature.getInstance("SHA256WITHRSAENCRYPTION");
+ OpenSSLSignature.getInstance("SHA384WITHRSAENCRYPTION");
+ OpenSSLSignature.getInstance("SHA512WITHRSAENCRYPTION");
+ } catch (NoSuchAlgorithmException e) {
+ fail("getInstance is not case insensitive");
+ }
+ }
+}
diff --git a/luni/src/test/java/tests/api/java/util/BitSetTest.java b/luni/src/test/java/tests/api/java/util/BitSetTest.java
index 172c6d1..e1abc48 100644
--- a/luni/src/test/java/tests/api/java/util/BitSetTest.java
+++ b/luni/src/test/java/tests/api/java/util/BitSetTest.java
@@ -1178,6 +1178,33 @@
// if the index is larger than bs.size(), nextClearBit should return index
assertEquals(513, bs.nextClearBit(513));
assertEquals(800, bs.nextClearBit(800));
+
+ bs.clear();
+ assertEquals(0, bs.nextClearBit(0));
+ assertEquals(3, bs.nextClearBit(3));
+ assertEquals(64, bs.nextClearBit(64));
+ assertEquals(128, bs.nextClearBit(128));
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=31036
+ public void test_31036_clear() {
+ BitSet bs = new BitSet(500);
+ for (int i = 0; i < 500; ++i) {
+ int nextClear = bs.nextClearBit(0);
+ assertEquals(i, nextClear);
+ bs.set(i);
+ }
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=31036
+ public void test_31036_set() {
+ BitSet bs = new BitSet(500);
+ bs.set(0, 511);
+ for (int i = 0; i < 500; ++i) {
+ int nextSet = bs.nextSetBit(0);
+ assertEquals(i, nextSet);
+ bs.clear(i);
+ }
}
public void test_isEmpty() {
diff --git a/luni/src/test/java/tests/api/java/util/CalendarTest.java b/luni/src/test/java/tests/api/java/util/CalendarTest.java
index ce31216..54524ad 100644
--- a/luni/src/test/java/tests/api/java/util/CalendarTest.java
+++ b/luni/src/test/java/tests/api/java/util/CalendarTest.java
@@ -654,10 +654,10 @@
public void test_getInstance() {
// test getInstance(Locale)
Calendar us_calendar = Calendar.getInstance(Locale.US);
- Calendar ch_calendar = Calendar.getInstance(Locale.CHINESE);
+ Calendar de_calendar = Calendar.getInstance(Locale.GERMAN);
assertEquals(Calendar.SUNDAY, us_calendar
.getFirstDayOfWeek());
- assertEquals(Calendar.MONDAY, ch_calendar
+ assertEquals(Calendar.MONDAY, de_calendar
.getFirstDayOfWeek());
// test getInstance(Locale, TimeZone)
diff --git a/luni/src/test/java/tests/api/java/util/CurrencyTest.java b/luni/src/test/java/tests/api/java/util/CurrencyTest.java
index 9571b73..c43d339 100644
--- a/luni/src/test/java/tests/api/java/util/CurrencyTest.java
+++ b/luni/src/test/java/tests/api/java/util/CurrencyTest.java
@@ -136,16 +136,15 @@
// BEGIN android-changed
// KRW currency symbol is \u20a9 since CLDR1.7 release.
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
+ // IEP currency symbol is IEP since CLDR2.0 release.
+ assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
// END android-changed
- assertEquals("currI.getSymbol()", "IR\u00a3", currI.getSymbol());
assertEquals("currUS.getSymbol()", "$", currUS.getSymbol());
Locale.setDefault(new Locale("en", "IE"));
// BEGIN android-changed
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
- // END android-changed
- assertEquals("currI.getSymbol()", "IR\u00a3", currI.getSymbol());
- // BEGIN android-changed
+ assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
assertEquals("currUS.getSymbol()", "$", currUS.getSymbol());
// END android-changed
@@ -154,8 +153,8 @@
Locale.setDefault(new Locale("kr", "KR"));
// BEGIN android-changed
assertEquals("currK.getSymbol()", "\u20a9", currK.getSymbol());
+ assertEquals("currI.getSymbol()", "IEP", currI.getSymbol());
// END android-changed
- assertEquals("currI.getSymbol()", "IR\u00a3", currI.getSymbol());
assertEquals("currUS.getSymbol()", "$", currUS.getSymbol());
}
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/CertificatesToPlayWith.java b/luni/src/test/java/tests/api/javax/net/ssl/CertificatesToPlayWith.java
index 60af3c3..5bb6f06 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/CertificatesToPlayWith.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/CertificatesToPlayWith.java
@@ -450,29 +450,29 @@
"2b8a9c7d91c7d175ae";
/**
- * subjectAlt=IP Address:127.0.0.1, email:oleg@ural.ru, DNS:localhost.localdomain
+ * cat cert.cnf
+ * [req]
+ * distinguished_name=distinguished_name
+ * req_extensions=req_extensions
+ * x509_extensions=x509_extensions
+ * [distinguished_name]
+ * [req_extensions]
+ * [x509_extensions]
+ * subjectAltName=DNS:localhost.localdomain,DNS:localhost,IP:127.0.0.1
+ *
+ * $ openssl req -x509 -nodes -days 36500 -subj '/CN=localhost' -config ./cert.cnf \
+ * -newkey rsa:512 -out cert.pem
*/
public final static byte[] X509_MULTIPLE_SUBJECT_ALT = (
"-----BEGIN CERTIFICATE-----\n" +
- "MIIDcTCCAtqgAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMQswCQYDVQQGEwJDSDEL\n" +
- "MAkGA1UECBMCWkgxDzANBgNVBAcTBlp1cmljaDETMBEGA1UEAxMKTXkgVGVzdCBD\n" +
- "QTAeFw0wODEwMzExMTU3NDVaFw0wOTEwMzExMTU3NDVaMGkxCzAJBgNVBAYTAkNI\n" +
- "MRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdV\n" +
- "bmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQDEwlsb2NhbGhvc3QwggG4\n" +
- "MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/\n" +
- "gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQ\n" +
- "IsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZ\n" +
- "ndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5\n" +
- "eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbh\n" +
- "PBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8G\n" +
- "kotmXoB7VSVkAUw7/s9JKgOBhQACgYEA6ogAb/YLM1Rz9AoXKW4LA70VtFf7Mqqp\n" +
- "divdu9f72WQc1vMKo1YMf3dQadkMfBYRvAAa1IXDnoiFCHhXnVRkWkoUBJyNebLB\n" +
- "N92CZc0RVFZiMFgQMEh8UldnvAIi4cBk0/YuN3BGl4MzmquVIGrFovdWGqeaveOu\n" +
- "Xcu4lKGJNiqjODA2MDQGA1UdEQQtMCuHBH8AAAGBDG9sZWdAdXJhbC5ydYIVbG9j\n" +
- "YWxob3N0LmxvY2FsZG9tYWluMA0GCSqGSIb3DQEBBQUAA4GBAIgEwIoCSRkU3O7K\n" +
- "USYaOYyfJB9hsvs6YpClvYXiQ/5kPGARP60pM62v4wC7wI9shEizokIAxY2+O3cC\n" +
- "vwuJhNYaa2FJMELIwRN3XES8X8R6JHWbPaRjaAAPhczuEd8SZYy8yiVLmJTgw0gH\n" +
- "BSW775NHlkjsscFVgXkNf0PobqJ9\n" +
+ "MIIBWDCCAQKgAwIBAgIJANS1EtICX2AZMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV\n" +
+ "BAMTCWxvY2FsaG9zdDAgFw0xMjAxMDIxOTA4NThaGA8yMTExMTIwOTE5MDg1OFow\n" +
+ "FDESMBAGA1UEAxMJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPpt\n" +
+ "atK8r4/hf4hSIs0os/BSlQLbRBaK9AfBReM4QdAklcQqe6CHsStKfI8pp0zs7Ptg\n" +
+ "PmMdpbttL0O7mUboBC8CAwEAAaM1MDMwMQYDVR0RBCowKIIVbG9jYWxob3N0Lmxv\n" +
+ "Y2FsZG9tYWlugglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADQQD0ntfL\n" +
+ "DCzOCv9Ma6Lv5o5jcYWVxvBSTsnt22hsJpWD1K7iY9lbkLwl0ivn73pG2evsAn9G\n" +
+ "X8YKH52fnHsCrhSD\n" +
"-----END CERTIFICATE-----").getBytes();
}
diff --git a/luni/src/test/java/tests/api/javax/net/ssl/HostnameVerifierTest.java b/luni/src/test/java/tests/api/javax/net/ssl/HostnameVerifierTest.java
index 253fed2..839f3b5 100644
--- a/luni/src/test/java/tests/api/javax/net/ssl/HostnameVerifierTest.java
+++ b/luni/src/test/java/tests/api/javax/net/ssl/HostnameVerifierTest.java
@@ -19,20 +19,14 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
-import java.net.URL;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal;
import junit.framework.TestCase;
import org.apache.harmony.xnet.tests.support.mySSLSession;
-/**
- * Tests for <code>HostnameVerifier</code> class constructors and methods.
- *
- */
public class HostnameVerifierTest extends TestCase implements
CertificatesToPlayWith {
@@ -69,7 +63,7 @@
in = new ByteArrayInputStream(X509_FOO_BAR);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertFalse(verifier.verify("a.foo.com", session));
assertTrue(verifier.verify("bar.com", session));
assertFalse(verifier.verify("a.bar.com", session));
@@ -113,25 +107,25 @@
in = new ByteArrayInputStream(X509_WILD_FOO);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
- assertFalse(verifier.verify("foo.com", session));
+ assertTrue(verifier.verify("foo.com", session));
assertTrue(verifier.verify("www.foo.com", session));
assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
- assertTrue(verifier.verify("a.b.foo.com", session));
+ assertFalse(verifier.verify("a.b.foo.com", session));
in = new ByteArrayInputStream(X509_WILD_CO_JP);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
- assertFalse(verifier.verify("foo.co.jp", session));
- assertFalse(verifier.verify("\u82b1\u5b50.co.jp", session));
+ assertTrue(verifier.verify("foo.co.jp", session));
+ assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
in = new ByteArrayInputStream(X509_WILD_FOO_BAR_HANAKO);
x509 = (X509Certificate) cf.generateCertificate(in);
session = new mySSLSession(new X509Certificate[] {x509});
// try the foo.com variations
- assertFalse(verifier.verify("foo.com", session));
+ assertTrue(verifier.verify("foo.com", session));
assertTrue(verifier.verify("www.foo.com", session));
assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
- assertTrue(verifier.verify("a.b.foo.com", session));
+ assertFalse(verifier.verify("a.b.foo.com", session));
// these checks test alternative subjects. The test data contains an
// alternative subject starting with a japanese kanji character. This is
// not supported by Android because the underlying implementation from
@@ -150,9 +144,7 @@
mySSLSession session = new mySSLSession(new X509Certificate[] {x509});
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
- String expected = "CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=CH";
- assertEquals(new X500Principal(expected),
- x509.getSubjectX500Principal());
+ assertEquals(new X500Principal("CN=localhost"), x509.getSubjectX500Principal());
assertTrue(verifier.verify("localhost", session));
assertTrue(verifier.verify("localhost.localdomain", session));
@@ -192,7 +184,13 @@
assertFalse(verifier.verify("127.0.0.1", session));
}
- public void testWildcardsMustHaveTwoDots() throws Exception {
+ /**
+ * Earlier implementations of Android's hostname verifier required that
+ * wildcard names wouldn't match "*.com" or similar. This was a nonstandard
+ * check that we've since dropped. It is the CA's responsibility to not hand
+ * out certificates that match so broadly.
+ */
+ public void testWildcardsDoesNotNeedTwoDots() throws Exception {
// openssl req -x509 -nodes -days 36500 -subj '/CN=*.com' -newkey rsa:512 -out cert.pem
String cert = "-----BEGIN CERTIFICATE-----\n"
+ "MIIBjDCCATagAwIBAgIJAOVulXCSu6HuMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNV\n"
@@ -211,7 +209,7 @@
mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
- assertFalse(verifier.verify("google.com", session));
+ assertTrue(verifier.verify("google.com", session));
}
public void testSubjectAltName() throws Exception {
@@ -244,7 +242,7 @@
mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertTrue(verifier.verify("bar.com", session));
assertTrue(verifier.verify("baz.com", session));
assertFalse(verifier.verify("a.foo.com", session));
@@ -281,10 +279,10 @@
mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
- assertTrue(verifier.verify("foo.com", session));
+ assertFalse(verifier.verify("foo.com", session));
assertTrue(verifier.verify("bar.com", session));
assertTrue(verifier.verify("a.baz.com", session));
- assertFalse(verifier.verify("baz.com", session));
+ assertTrue(verifier.verify("baz.com", session));
assertFalse(verifier.verify("a.foo.com", session));
assertFalse(verifier.verify("a.bar.com", session));
assertFalse(verifier.verify("quux.com", session));
diff --git a/luni/src/test/java/tests/api/javax/security/auth/DestroyFailedExceptionTest.java b/luni/src/test/java/tests/api/javax/security/auth/DestroyFailedExceptionTest.java
index 3fb3d97..4472241 100644
--- a/luni/src/test/java/tests/api/javax/security/auth/DestroyFailedExceptionTest.java
+++ b/luni/src/test/java/tests/api/javax/security/auth/DestroyFailedExceptionTest.java
@@ -27,18 +27,6 @@
*/
public class DestroyFailedExceptionTest extends TestCase {
- public static void main(String[] args) {
- }
-
- /**
- * Constructor for DestroyFailedExceptionTest.
- *
- * @param arg0
- */
- public DestroyFailedExceptionTest(String arg0) {
- super(arg0);
- }
-
private static String[] msgs = {
"",
"Check new message",
diff --git a/luni/src/test/java/tests/api/javax/security/auth/LoginExceptionTest.java b/luni/src/test/java/tests/api/javax/security/auth/LoginExceptionTest.java
index ef53a98..307d401 100644
--- a/luni/src/test/java/tests/api/javax/security/auth/LoginExceptionTest.java
+++ b/luni/src/test/java/tests/api/javax/security/auth/LoginExceptionTest.java
@@ -27,18 +27,6 @@
*/
public class LoginExceptionTest extends TestCase {
- public static void main(String[] args) {
- }
-
- /**
- * Constructor for LoginExceptionTest.
- *
- * @param arg0
- */
- public LoginExceptionTest(String arg0) {
- super(arg0);
- }
-
private static String[] msgs = {
"",
"Check new message",
diff --git a/luni/src/test/java/tests/api/javax/security/auth/UnsupportedCallbackExceptionTest.java b/luni/src/test/java/tests/api/javax/security/auth/UnsupportedCallbackExceptionTest.java
index ac41d69..abef563 100644
--- a/luni/src/test/java/tests/api/javax/security/auth/UnsupportedCallbackExceptionTest.java
+++ b/luni/src/test/java/tests/api/javax/security/auth/UnsupportedCallbackExceptionTest.java
@@ -28,18 +28,6 @@
*/
public class UnsupportedCallbackExceptionTest extends TestCase {
- public static void main(String[] args) {
- }
-
- /**
- * Constructor for UnsupportedCallbackExceptionTest.
- *
- * @param arg0
- */
- public UnsupportedCallbackExceptionTest(String arg0) {
- super(arg0);
- }
-
private static String[] msgs = {
"",
"Check new message",
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedCollection.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedCollection.golden.ser
deleted file mode 100644
index eec840e..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedCollection.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedList.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedList.golden.ser
deleted file mode 100644
index e9a4122..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedList.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedListRandomAccess.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedListRandomAccess.golden.ser
deleted file mode 100644
index dfa2d43..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedListRandomAccess.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedMap.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedMap.golden.ser
deleted file mode 100644
index 13415f6..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedMap.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSet.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSet.golden.ser
deleted file mode 100644
index ed1f305..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSet.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedMap.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedMap.golden.ser
deleted file mode 100644
index eca8ffa..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedMap.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedSet.golden.ser b/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedSet.golden.ser
deleted file mode 100644
index 4520ed4..0000000
--- a/luni/src/test/resources/serialization/org/apache/harmony/luni/tests/java/util/Collections_CheckedSortedSet.golden.ser
+++ /dev/null
Binary files differ
diff --git a/luni/src/test/resources/serialization/tests/api/java/util/PriorityQueue.golden.ser b/luni/src/test/resources/serialization/tests/api/java/util/PriorityQueue.golden.ser
deleted file mode 100644
index d716dda..0000000
--- a/luni/src/test/resources/serialization/tests/api/java/util/PriorityQueue.golden.ser
+++ /dev/null
Binary files differ
diff --git a/support/src/test/java/libcore/dalvik/system/CloseGuardTester.java b/support/src/test/java/libcore/dalvik/system/CloseGuardTester.java
index 4ed59a2..e82d33d 100644
--- a/support/src/test/java/libcore/dalvik/system/CloseGuardTester.java
+++ b/support/src/test/java/libcore/dalvik/system/CloseGuardTester.java
@@ -26,6 +26,7 @@
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import junit.framework.Assert;
+import libcore.java.lang.ref.FinalizationTester;
public final class CloseGuardTester implements Closeable {
@@ -45,14 +46,12 @@
* Collect immediately before we start monitoring the CloseGuard logs.
* This lowers the chance that we'll report an unrelated leak.
*/
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
logger.addHandler(logWatcher);
}
public void assertEverythingWasClosed() {
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
if (!logRecords.isEmpty()) {
// print the log records with the output of this test
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 12f85397..e8b29e4 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -172,6 +172,8 @@
provide("Policy", "JavaPolicy");
provide("SSLContext", "SSLv3");
provide("SSLContext", "TLSv1");
+ provide("SSLContext", "TLSv1.1");
+ provide("SSLContext", "TLSv1.2");
provide("SecretKeyFactory", "DES");
provide("SecretKeyFactory", "DESede");
provide("SecretKeyFactory", "PBEWithMD5AndDES");
@@ -448,7 +450,9 @@
// "SSLv2",
"SSLv3",
"TLS",
- "TLSv1"));
+ "TLSv1",
+ "TLSv1.1",
+ "TLSv1.2"));
public static final String SSL_CONTEXT_PROTOCOL_DEFAULT = "TLS";
public static final Set<String> KEY_TYPES = new HashSet<String>(Arrays.asList(
@@ -464,7 +468,9 @@
public static final Set<String> SSL_SOCKET_PROTOCOLS = new HashSet<String>(Arrays.asList(
// "SSLv2",
"SSLv3",
- "TLSv1"));
+ "TLSv1",
+ "TLSv1.1",
+ "TLSv1.2"));
static {
if (IS_RI) {
/* Even though we use OpenSSL's SSLv23_method which
@@ -474,9 +480,15 @@
* do to disable general use of SSLv2.
*/
SSL_SOCKET_PROTOCOLS.add("SSLv2Hello");
+ }
+ }
- SSL_SOCKET_PROTOCOLS.add("TLSv1.1");
- SSL_SOCKET_PROTOCOLS.add("TLSv1.2");
+ public static final Set<String> SSL_SOCKET_PROTOCOLS_SSLENGINE = new HashSet<String>(SSL_SOCKET_PROTOCOLS);
+ static {
+ // No TLSv1.1 or TLSv1.2 support on SSLEngine based provider
+ if (!IS_RI) {
+ SSL_SOCKET_PROTOCOLS_SSLENGINE.remove("TLSv1.1");
+ SSL_SOCKET_PROTOCOLS_SSLENGINE.remove("TLSv1.2");
}
}
@@ -798,7 +810,7 @@
assertTrue(protocols.length != 0);
// Make sure all protocols names are expected
- Set remainingProtocols = new HashSet<String>(StandardNames.SSL_SOCKET_PROTOCOLS);
+ Set remainingProtocols = new HashSet<String>(expected);
Set unknownProtocols = new HashSet<String>();
for (String protocol : protocols) {
if (!remainingProtocols.remove(protocol)) {
diff --git a/support/src/test/java/libcore/java/security/TestKeyStore.java b/support/src/test/java/libcore/java/security/TestKeyStore.java
index 30e40fb..e24ee78 100644
--- a/support/src/test/java/libcore/java/security/TestKeyStore.java
+++ b/support/src/test/java/libcore/java/security/TestKeyStore.java
@@ -387,7 +387,8 @@
// 1.) we make the keys
int keySize;
if (keyAlgorithm.equals("RSA")) {
- keySize = StandardNames.IS_RI ? 1024 : 512; // 512 breaks SSL_RSA_EXPORT_* on RI
+ // 512 breaks SSL_RSA_EXPORT_* on RI and TLS_ECDHE_RSA_WITH_RC4_128_SHA for us
+ keySize = 1024;
} else if (keyAlgorithm.equals("DSA")) {
keySize = 512;
} else if (keyAlgorithm.equals("EC")) {
diff --git a/support/src/test/java/tests/security/KeyFactoryTest.java b/support/src/test/java/tests/security/KeyFactoryTest.java
index e2f687d..1d55c52 100644
--- a/support/src/test/java/tests/security/KeyFactoryTest.java
+++ b/support/src/test/java/tests/security/KeyFactoryTest.java
@@ -46,50 +46,17 @@
factory = getFactory();
}
- private KeyFactory getFactory() {
- try {
- return KeyFactory.getInstance(algorithmName);
- } catch (NoSuchAlgorithmException e) {
- fail(e.getMessage());
- }
- return null;
+ private KeyFactory getFactory() throws Exception {
+ return KeyFactory.getInstance(algorithmName);
}
- public void testKeyFactory() {
- PrivateKeySpec privateKeySpec = null;
- try {
- privateKeySpec = factory.getKeySpec(DefaultKeys.getPrivateKey(algorithmName),
- privateKeySpecClass);
- } catch (InvalidKeySpecException e) {
- fail(e.getMessage());
- } catch (NoSuchAlgorithmException e) {
- fail(e.getMessage());
- }
-
- PrivateKey privateKey = null;
- try {
- privateKey = factory.generatePrivate(privateKeySpec);
- } catch (InvalidKeySpecException e) {
- fail(e.getMessage());
- }
-
- PublicKeySpec publicKeySpec = null;
- try {
- publicKeySpec = factory.getKeySpec(DefaultKeys.getPublicKey(algorithmName),
- publicKeySpecClass);
- } catch (InvalidKeySpecException e) {
- fail(e.getMessage());
- } catch (NoSuchAlgorithmException e) {
- fail(e.getMessage());
- }
-
- PublicKey publicKey = null;
- try {
- publicKey = factory.generatePublic(publicKeySpec);
- } catch (InvalidKeySpecException e) {
- fail(e.getMessage());
- }
-
+ public void testKeyFactory() throws Exception {
+ PrivateKeySpec privateKeySpec = factory.getKeySpec(DefaultKeys.getPrivateKey(algorithmName),
+ privateKeySpecClass);
+ PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
+ PublicKeySpec publicKeySpec = factory.getKeySpec(DefaultKeys.getPublicKey(algorithmName),
+ publicKeySpecClass);
+ PublicKey publicKey = factory.generatePublic(publicKeySpec);
check(new KeyPair(publicKey, privateKey));
}
diff --git a/support/src/test/java/tests/util/SerializationTester.java b/support/src/test/java/tests/util/SerializationTester.java
deleted file mode 100644
index bd9bc93..0000000
--- a/support/src/test/java/tests/util/SerializationTester.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 tests.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.net.URL;
-
-/**
- * This class simplifies the serialization test.
- *
- */
-public class SerializationTester {
-
- /*
- * --------------------------------------------------------------------
- * Class variables
- * --------------------------------------------------------------------
- */
-
- // the last deserialized object
- private static Object lastOutput = null;
-
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
- private SerializationTester() {
-
- }
-
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
- /**
- * Serialize an object and then deserialize it.
- *
- * @param inputObject
- * the input object
- * @return the deserialized object
- */
- public static <T> T getDeserializedObject(T inputObject)
- throws IOException, ClassNotFoundException {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(bos);
- oos.writeObject(inputObject);
- oos.close();
-
- ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- ObjectInputStream ois = new ObjectInputStream(bis);
- Object outputObject = ois.readObject();
- lastOutput = outputObject;
- ois.close();
- return (T) outputObject;
- }
-
- /**
- * Tests the serialization and deserialization of const objects.
- *
- * @param inputObject
- * A const object
- * @return true if the deserialized object is the same as the input object,
- * otherwise false
- * @throws Exception
- * If any occurs.
- */
- public static boolean assertSame(Object inputObject) throws Exception {
- return inputObject == getDeserializedObject(inputObject);
- }
-
- /**
- * Tests the serialization and deserialization of instance objects.
- *
- * @param inputObject
- * An object
- * @return true if the deserialized object is equal to the input object,
- * otherwise false
- * @throws Exception
- * If any occurs.
- */
- public static boolean assertEquals(Object inputObject) throws Exception {
- return inputObject.equals(getDeserializedObject(inputObject));
- }
-
- /**
- * Tests the serialization compatibility with reference const objects.
- *
- * @param obj
- * the object to be checked
- * @param fileName
- * the serialization output file generated by reference
- * @return true if compatible, otherwise false
- * @throws Exception
- * If any occurs.
- */
- public static boolean assertCompatibilitySame(Object obj, String fileName)
- throws Exception {
- return obj == readObject(obj, fileName);
- }
-
- /**
- * Tests the serialization compatibility with reference for instance
- * objects.
- *
- * @param obj
- * the object to be checked
- * @param fileName
- * the serialization output file generated by reference
- * @return true if compatible, otherwise false
- * @throws Exception
- * If any occurs.
- */
- public static boolean assertCompatibilityEquals(Object obj, String fileName)
- throws Exception {
- return obj.equals(readObject(obj, fileName));
- }
-
- /**
- * Deserialize an object from a file.
- *
- * @param obj
- * the object to be serialized if no serialization file is found
- * @param fileName
- * the serialization file
- * @return the deserialized object
- * @throws Exception
- * If any occurs.
- */
- public static Object readObject(Object obj, String fileName)
- throws Exception {
- InputStream input = null;
- ObjectInputStream oinput = null;
- URL url = SerializationTester.class.getResource(
- fileName);
- if (null == url) {
- // serialization file does not exist, create one in the current dir
- writeObject(obj, new File(fileName).getName());
- throw new Error(
- "Serialization file does not exist, created in the current dir.");
- }
- input = url.openStream();
- try {
- oinput = new ObjectInputStream(input);
- Object newObj = oinput.readObject();
- return newObj;
- } finally {
- try {
- if (null != oinput) {
- oinput.close();
- }
- } catch (Exception e) {
- // ignore
- }
- try {
- if (null != input) {
- input.close();
- }
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- /*
- * Creates a serialization output.
- *
- * @param obj the object to be serialized @param fileName the output file
- * @throws Exception If any occurs.
- */
- public static void writeObject(Object obj, String fileName)
- throws Exception {
- // String path = SerializationTester.class.getResource(".").getPath();
- // if (path.endsWith(".")) {
- // path = path.substring(0, path.length() - 1);
- // }
- // if (!path.endsWith("/")) {
- // path += "/";
- // }
- // path += fileName;
- // System.out.println(path);
- OutputStream output = null;
- ObjectOutputStream ooutput = null;
- try {
- output = new FileOutputStream(fileName);
- ooutput = new ObjectOutputStream(output);
- ooutput.writeObject(obj);
- } finally {
- try {
- if (null != ooutput) {
- ooutput.close();
- }
- } catch (Exception e) {
- // ignore
- }
- try {
- if (null != output) {
- output.close();
- }
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- /**
- * Gets the last deserialized object.
- *
- * @return the last deserialized object
- */
- public static Object getLastOutput() {
- return lastOutput;
- }
-
- /*
- * For test purpose.
- */
- public static void main(String[] args) {
- }
-}
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
index 36e6025..e042eb8 100644
--- a/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
+++ b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
@@ -112,6 +112,7 @@
* Start tag foo
* Text Hello World!
* End tag foo
+ * End document
* </pre>
*
* <p>For more details on API usage, please refer to the
@@ -160,9 +161,9 @@
* Logical end of the xml document. Returned from getEventType, next()
* and nextToken()
* when the end of the input document has been reached.
- * <p><strong>NOTE:</strong> calling again
+ * <p><strong>NOTE:</strong> subsequent calls to
* <a href="#next()">next()</a> or <a href="#nextToken()">nextToken()</a>
- * will result in exception being thrown.
+ * may result in exception being thrown.
*
* @see #next
* @see #nextToken
@@ -1051,7 +1052,7 @@
* If current event is START_TAG then if next element is TEXT then element content is returned
* or if next event is END_TAG then empty string is returned, otherwise exception is thrown.
* After calling this function successfully parser will be positioned on END_TAG.
- *
+ *
* <p>The motivation for this function is to allow to parse consistently both
* empty elements and elements that has non empty content, for example for input: <ol>
* <li><tag>foo</tag>
@@ -1089,6 +1090,15 @@
* "parser must be on START_TAG or TEXT to read text", this, null);
* }
* </pre>
+ *
+ * <p><strong>Warning:</strong> Prior to API level 14, the pull parser returned by {@code
+ * android.util.Xml} did not always advance to the END_TAG event when this method was called.
+ * Work around by using manually advancing after calls to nextText(): <pre>
+ * String text = xpp.nextText();
+ * if (xpp.getEventType() != XmlPullParser.END_TAG) {
+ * xpp.next();
+ * }
+ * </pre>
*/
String nextText() throws XmlPullParserException, IOException;