You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2019/11/08 09:43:14 UTC

[httpcomponents-client] branch master updated (33cfaed -> e1f48e7)

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git.


 discard 33cfaed  HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer
     new e1f48e7  HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (33cfaed)
            \
             N -- N -- N   refs/heads/master (e1f48e7)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../impl/cache/ByteArrayCacheEntrySerializer.java  |  74 ++++----
 .../cache/TestByteArrayCacheEntrySerializer.java   | 196 ++++++++++++++++++---
 2 files changed, 205 insertions(+), 65 deletions(-)


[httpcomponents-client] 01/01: HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer

Posted by ol...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit e1f48e788d1a9958eedbb9a42ecca0ebc6d8718d
Author: Olof Larsson <ol...@sylt.nu>
AuthorDate: Wed Nov 6 18:02:20 2019 +0100

    HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer
---
 .../impl/cache/ByteArrayCacheEntrySerializer.java  |  66 ++++---
 .../cache/TestByteArrayCacheEntrySerializer.java   | 196 ++++++++++++++++++---
 2 files changed, 205 insertions(+), 57 deletions(-)

diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ByteArrayCacheEntrySerializer.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ByteArrayCacheEntrySerializer.java
index c15352c..edef053 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ByteArrayCacheEntrySerializer.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ByteArrayCacheEntrySerializer.java
@@ -55,24 +55,8 @@ import org.apache.hc.core5.annotation.ThreadingBehavior;
 @Contract(threading = ThreadingBehavior.STATELESS)
 public final class ByteArrayCacheEntrySerializer implements HttpCacheEntrySerializer<byte[]> {
 
-    private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
-            Pattern.compile("^(\\[L)?org\\.apache\\.hc\\.(.*)"),
-            Pattern.compile("^(\\[L)?java\\.util\\.(.*)"),
-            Pattern.compile("^(\\[L)?java\\.lang\\.(.*)$"),
-            Pattern.compile("^\\[B$")));
-
     public static final ByteArrayCacheEntrySerializer INSTANCE = new ByteArrayCacheEntrySerializer();
 
-    private final List<Pattern> allowedClassPatterns;
-
-    ByteArrayCacheEntrySerializer(final Pattern... allowedClassPatterns) {
-        this.allowedClassPatterns = Collections.unmodifiableList(Arrays.asList(allowedClassPatterns));
-    }
-
-    public ByteArrayCacheEntrySerializer() {
-        this.allowedClassPatterns = ALLOWED_CLASS_PATTERNS;
-    }
-
     @Override
     public byte[] serialize(final HttpCacheStorageEntry cacheEntry) throws ResourceIOException {
         if (cacheEntry == null) {
@@ -92,42 +76,54 @@ public final class ByteArrayCacheEntrySerializer implements HttpCacheEntrySerial
         if (serializedObject == null) {
             return null;
         }
-        try (final ObjectInputStream ois = new RestrictedObjectInputStream(
-                new ByteArrayInputStream(serializedObject), allowedClassPatterns)) {
+        try (final ObjectInputStream ois = new RestrictedObjectInputStream(new ByteArrayInputStream(serializedObject))) {
             return (HttpCacheStorageEntry) ois.readObject();
         } catch (final IOException | ClassNotFoundException ex) {
             throw new ResourceIOException(ex.getMessage(), ex);
         }
     }
 
-    private static class RestrictedObjectInputStream extends ObjectInputStream {
-
-        private final List<Pattern> allowedClassPatterns;
-
-        private RestrictedObjectInputStream(final InputStream in, final List<Pattern> patterns) throws IOException {
+    // visible for testing
+    static class RestrictedObjectInputStream extends ObjectInputStream {
+
+        private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
+                Pattern.compile("^(\\[L)?org\\.apache\\.hc\\.(.*)"),
+                Pattern.compile("^(?:\\[+L)?java\\.util\\..*$"),
+                Pattern.compile("^(?:\\[+L)?java\\.lang\\..*$"),
+                Pattern.compile("^\\[+Z$"), // boolean
+                Pattern.compile("^\\[+B$"), // byte
+                Pattern.compile("^\\[+C$"), // char
+                Pattern.compile("^\\[+D$"), // double
+                Pattern.compile("^\\[+F$"), // float
+                Pattern.compile("^\\[+I$"), // int
+                Pattern.compile("^\\[+J$"), // long
+                Pattern.compile("^\\[+S$") // short
+        ));
+
+        private RestrictedObjectInputStream(final InputStream in) throws IOException {
             super(in);
-            this.allowedClassPatterns = patterns;
         }
 
         @Override
-        protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException {
-            if (isProhibited(desc)) {
+        protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
+            final String className = objectStreamClass.getName();
+            if (!isAllowedClassName(className)) {
                 throw new ResourceIOException(String.format(
-                        "Class %s is not allowed for deserialization", desc.getName()));
+                        "Class %s is not allowed for deserialization", objectStreamClass.getName()));
             }
-            return super.resolveClass(desc);
+            return super.resolveClass(objectStreamClass);
         }
 
-        private boolean isProhibited(final ObjectStreamClass desc) {
-            if (allowedClassPatterns != null) {
-                for (final Pattern pattern : allowedClassPatterns) {
-                    if (pattern.matcher(desc.getName()).matches()) {
-                        return false;
-                    }
+        // visible for testing
+        static boolean isAllowedClassName(final String className) {
+            for (final Pattern allowedClassPattern : ALLOWED_CLASS_PATTERNS) {
+                if (allowedClassPattern.matcher(className).matches()) {
+                    return true;
                 }
             }
-            return true;
+            return false;
         }
+
     }
 
 }
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestByteArrayCacheEntrySerializer.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestByteArrayCacheEntrySerializer.java
index 98f8c18..17cf8d9 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestByteArrayCacheEntrySerializer.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestByteArrayCacheEntrySerializer.java
@@ -27,23 +27,25 @@
 package org.apache.hc.client5.http.impl.cache;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 import org.apache.hc.client5.http.cache.HttpCacheEntry;
 import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
-import org.apache.hc.client5.http.cache.ResourceIOException;
+import org.apache.hc.client5.http.cache.Resource;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.StatusLine;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -51,8 +53,6 @@ import com.sun.rowset.JdbcRowSetImpl;
 
 public class TestByteArrayCacheEntrySerializer {
 
-    private static final Charset UTF8 = Charset.forName("UTF-8");
-
     private ByteArrayCacheEntrySerializer impl;
 
     @Before
@@ -62,28 +62,180 @@ public class TestByteArrayCacheEntrySerializer {
 
     @Test
     public void canSerializeEntriesWithVariantMaps() throws Exception {
-        readWriteVerify(makeCacheEntryWithVariantMap("key"));
+        readWriteVerify(makeCacheEntryWithVariantMap("somekey"));
+    }
+
+    @Test
+    public void isAllowedClassNameStringTrue() {
+        assertIsAllowedClassNameTrue(String.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameStringArrayTrue() {
+        assertIsAllowedClassNameTrue("[L" + String.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameStringArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[L" + String.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameDataTrue() {
+        assertIsAllowedClassNameTrue(Date.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameStatusLineTrue() {
+        assertIsAllowedClassNameTrue(StatusLine.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameResourceTrue() {
+        assertIsAllowedClassNameTrue(Resource.class.getName());
+    }
+
+    @Test
+    public void isAllowedClassNameByteArrayTrue() {
+        assertIsAllowedClassNameTrue("[B");
+    }
+
+    @Test
+    public void isAllowedClassNameByteArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[B");
+    }
+
+    @Test
+    public void isAllowedClassNameCharArrayTrue() {
+        assertIsAllowedClassNameTrue("[C");
+    }
+
+    @Test
+    public void isAllowedClassNameCharArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[C");
+    }
+
+    @Test
+    public void isAllowedClassNameDoubleArrayTrue() {
+        assertIsAllowedClassNameTrue("[D");
+    }
+
+    @Test
+    public void isAllowedClassNameDoubleArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[D");
+    }
+
+    @Test
+    public void isAllowedClassNameFloatArrayTrue() {
+        assertIsAllowedClassNameTrue("[F");
+    }
+
+    @Test
+    public void isAllowedClassNameFloatArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[F");
+    }
+
+    @Test
+    public void isAllowedClassNameIntArrayTrue() {
+        assertIsAllowedClassNameTrue("[I");
+    }
+
+    @Test
+    public void isAllowedClassNameIntArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[I");
     }
 
-    @Test(expected = ResourceIOException.class)
-    public void throwExceptionIfUnsafeDeserialization() throws IOException {
-        impl.deserialize(serializeProhibitedObject());
+    @Test
+    public void isAllowedClassNameLongArrayTrue() {
+        assertIsAllowedClassNameTrue("[J");
+    }
+
+    @Test
+    public void isAllowedClassNameLongArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[J");
+    }
+
+    @Test
+    public void isAllowedClassNameShortArrayTrue() {
+        assertIsAllowedClassNameTrue("[S");
+    }
+
+    @Test
+    public void isAllowedClassNameShortArrayArrayTrue() {
+        assertIsAllowedClassNameTrue("[[S");
+    }
+
+    @Test
+    public void isAllowedClassNameCollectionsInvokerTransformerFalse() {
+        assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InvokerTransformer");
+    }
+
+    @Test
+    public void isAllowedClassNameCollections4InvokerTransformerFalse() {
+        assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InvokerTransformer");
+    }
+
+    @Test
+    public void isAllowedClassNameCollectionsInstantiateTransformerFalse() {
+        assertIsAllowedClassNameFalse("org.apache.commons.collections.functors.InstantiateTransformer");
+    }
+
+    @Test
+    public void isAllowedClassNameCollections4InstantiateTransformerFalse() {
+        assertIsAllowedClassNameFalse("org.apache.commons.collections4.functors.InstantiateTransformer");
+    }
+
+    @Test
+    public void isAllowedClassNameGroovyConvertedClosureFalse() {
+        assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.ConvertedClosure");
+    }
+
+    @Test
+    public void isAllowedClassNameGroovyMethodClosureFalse() {
+        assertIsAllowedClassNameFalse("org.codehaus.groovy.runtime.MethodClosure");
+    }
+
+    @Test
+    public void isAllowedClassNameSpringObjectFactoryFalse() {
+        assertIsAllowedClassNameFalse("org.springframework.beans.factory.ObjectFactory");
+    }
+
+    @Test
+    public void isAllowedClassNameCalanTemplatesImplFalse() {
+        assertIsAllowedClassNameFalse("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
+    }
+
+    @Test
+    public void isAllowedClassNameCalanTemplatesImplArrayFalse() {
+        assertIsAllowedClassNameFalse("[Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
+    }
+
+    @Test
+    public void isAllowedClassNameJavaRmiRegistryFalse() {
+        assertIsAllowedClassNameFalse("java.rmi.registry.Registry");
+    }
+
+    @Test
+    public void isAllowedClassNameJavaRmiServerRemoteObjectInvocationHandlerFalse() {
+        assertIsAllowedClassNameFalse("java.rmi.server.RemoteObjectInvocationHandler");
+    }
+
+    @Test
+    public void isAllowedClassNameJavaxXmlTransformTemplatesFalse() {
+        assertIsAllowedClassNameFalse("javax.xml.transform.Templates");
+    }
+
+    @Test
+    public void isAllowedClassNameJavaxManagementMBeanServerInvocationHandlerFalse() {
+        assertIsAllowedClassNameFalse("javax.management.MBeanServerInvocationHandler");
     }
 
-    @Test(expected = ResourceIOException.class)
-    public void allowClassesToBeDeserialized() throws IOException {
-        impl = new ByteArrayCacheEntrySerializer(
-                Pattern.compile("javax.sql.rowset.BaseRowSet"),
-                Pattern.compile("com.sun.rowset.JdbcRowSetImpl"));
-        impl.deserialize(serializeProhibitedObject());
+    private static void assertIsAllowedClassNameTrue(final String className) {
+        assertTrue(ByteArrayCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
     }
 
-    @Test(expected = ResourceIOException.class)
-    public void allowClassesToBeDeserializedByRegex() throws IOException {
-        impl = new ByteArrayCacheEntrySerializer(
-                Pattern.compile(("^com\\.sun\\.rowset\\.(.*)")),
-                Pattern.compile("^javax\\.sql\\.rowset\\.BaseRowSet$"));
-        impl.deserialize(serializeProhibitedObject());
+    private static void assertIsAllowedClassNameFalse(final String className) {
+        assertFalse(ByteArrayCacheEntrySerializer.RestrictedObjectInputStream.isAllowedClassName(className));
     }
 
     private byte[] serializeProhibitedObject() throws IOException {
@@ -123,7 +275,7 @@ public class TestByteArrayCacheEntrySerializer {
                 new Date(),
                 HttpStatus.SC_OK,
                 headers,
-                new HeapResource(body.getBytes(UTF8)), variantMap);
+                new HeapResource(body.getBytes(StandardCharsets.UTF_8)), variantMap);
 
         return new HttpCacheStorageEntry(key, cacheEntry);
     }