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.http.impl.client.cache;
28
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.ObjectInputStream;
32 import java.io.ObjectOutputStream;
33 import java.io.ObjectStreamClass;
34 import java.io.OutputStream;
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.regex.Pattern;
39
40 import org.apache.http.annotation.Contract;
41 import org.apache.http.annotation.ThreadingBehavior;
42 import org.apache.http.client.cache.HttpCacheEntry;
43 import org.apache.http.client.cache.HttpCacheEntrySerializationException;
44 import org.apache.http.client.cache.HttpCacheEntrySerializer;
45
46
47
48
49
50
51
52
53
54 @Contract(threading = ThreadingBehavior.IMMUTABLE)
55 public class DefaultHttpCacheEntrySerializer implements HttpCacheEntrySerializer {
56
57 @Override
58 public void writeTo(final HttpCacheEntry cacheEntry, final OutputStream os) throws IOException {
59 final ObjectOutputStream oos = new ObjectOutputStream(os);
60 try {
61 oos.writeObject(cacheEntry);
62 } finally {
63 oos.close();
64 }
65 }
66
67 @Override
68 public HttpCacheEntry readFrom(final InputStream is) throws IOException {
69 final ObjectInputStream ois = new RestrictedObjectInputStream(is);
70 try {
71 return (HttpCacheEntry) ois.readObject();
72 } catch (final ClassNotFoundException ex) {
73 throw new HttpCacheEntrySerializationException("Class not found: " + ex.getMessage(), ex);
74 } finally {
75 ois.close();
76 }
77 }
78
79
80 static class RestrictedObjectInputStream extends ObjectInputStream {
81
82 private static final List<Pattern> ALLOWED_CLASS_PATTERNS = Collections.unmodifiableList(Arrays.asList(
83 Pattern.compile("^(?:\\[+L)?org\\.apache\\.http\\..*$"),
84 Pattern.compile("^(?:\\[+L)?java\\.util\\..*$"),
85 Pattern.compile("^(?:\\[+L)?java\\.lang\\..*$"),
86 Pattern.compile("^\\[+Z$"),
87 Pattern.compile("^\\[+B$"),
88 Pattern.compile("^\\[+C$"),
89 Pattern.compile("^\\[+D$"),
90 Pattern.compile("^\\[+F$"),
91 Pattern.compile("^\\[+I$"),
92 Pattern.compile("^\\[+J$"),
93 Pattern.compile("^\\[+S$")
94 ));
95
96 private RestrictedObjectInputStream(final InputStream in) throws IOException {
97 super(in);
98 }
99
100 @Override
101 protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
102 final String className = objectStreamClass.getName();
103 if (!isAllowedClassName(className)) {
104 final String message = String.format("Class %s is not allowed for deserialization", className);
105 throw new HttpCacheEntrySerializationException(message);
106 }
107 return super.resolveClass(objectStreamClass);
108 }
109
110
111 static boolean isAllowedClassName(final String className) {
112 for (final Pattern allowedClassPattern : ALLOWED_CLASS_PATTERNS) {
113 if (allowedClassPattern.matcher(className).matches()) {
114 return true;
115 }
116 }
117 return false;
118 }
119
120 }
121
122 }