1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.cache;
28
29 import java.io.ByteArrayInputStream;
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.ObjectInputStream;
34 import java.io.ObjectOutputStream;
35 import java.io.ObjectStreamClass;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.regex.Pattern;
40
41 import org.apache.hc.client5.http.cache.HttpCacheEntrySerializer;
42 import org.apache.hc.client5.http.cache.HttpCacheStorageEntry;
43 import org.apache.hc.client5.http.cache.ResourceIOException;
44 import org.apache.hc.core5.annotation.Contract;
45 import org.apache.hc.core5.annotation.ThreadingBehavior;
46
47
48
49
50
51
52
53
54
55
56
57 @Deprecated
58 @Contract(threading = ThreadingBehavior.STATELESS)
59 public final class ByteArrayCacheEntrySerializer implements HttpCacheEntrySerializer<byte[]> {
60
61 public static final ByteArrayCacheEntrySerializer INSTANCE = new ByteArrayCacheEntrySerializer();
62
63 @Override
64 public byte[] serialize(final HttpCacheStorageEntry cacheEntry) throws ResourceIOException {
65 if (cacheEntry == null) {
66 return null;
67 }
68 final ByteArrayOutputStream buf = new ByteArrayOutputStream();
69 try (final ObjectOutputStream oos = new ObjectOutputStream(buf)) {
70 oos.writeObject(cacheEntry);
71 } catch (final IOException ex) {
72 throw new ResourceIOException(ex.getMessage(), ex);
73 }
74 return buf.toByteArray();
75 }
76
77 @Override
78 public HttpCacheStorageEntry deserialize(final byte[] serializedObject) throws ResourceIOException {
79 if (serializedObject == null) {
80 return null;
81 }
82 try (final ObjectInputStream ois = new RestrictedObjectInputStream(new ByteArrayInputStream(serializedObject))) {
83 return (HttpCacheStorageEntry) ois.readObject();
84 } catch (final IOException | ClassNotFoundException ex) {
85 throw new ResourceIOException(ex.getMessage(), ex);
86 }
87 }
88
89
90 static class RestrictedObjectInputStream extends ObjectInputStream {
91
92 private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
93 Pattern.compile("^(\\[L)?org\\.apache\\.hc\\.(.*)"),
94 Pattern.compile("^(?:\\[+L)?java\\.util\\..*$"),
95 Pattern.compile("^(?:\\[+L)?java\\.lang\\..*$"),
96 Pattern.compile("^(?:\\[+L)?java\\.time\\..*$"),
97 Pattern.compile("^\\[+Z$"),
98 Pattern.compile("^\\[+B$"),
99 Pattern.compile("^\\[+C$"),
100 Pattern.compile("^\\[+D$"),
101 Pattern.compile("^\\[+F$"),
102 Pattern.compile("^\\[+I$"),
103 Pattern.compile("^\\[+J$"),
104 Pattern.compile("^\\[+S$")
105 ));
106
107 private RestrictedObjectInputStream(final InputStream in) throws IOException {
108 super(in);
109 }
110
111 @Override
112 protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
113 final String className = objectStreamClass.getName();
114 if (!isAllowedClassName(className)) {
115 throw new ResourceIOException(String.format(
116 "Class %s is not allowed for deserialization", objectStreamClass.getName()));
117 }
118 return super.resolveClass(objectStreamClass);
119 }
120
121
122 static boolean isAllowedClassName(final String className) {
123 for (final Pattern allowedClassPattern : ALLOWED_CLASS_PATTERNS) {
124 if (allowedClassPattern.matcher(className).matches()) {
125 return true;
126 }
127 }
128 return false;
129 }
130
131 }
132
133 }