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
28
29
30
31
32
33
34 package info.magnolia.module.cache.filter;
35
36 import info.magnolia.cms.util.RequestHeaderUtil;
37 import info.magnolia.module.cache.util.GZipUtil;
38
39 import java.io.IOException;
40 import java.io.ObjectInputStream;
41 import java.io.ObjectOutputStream;
42 import java.io.Serializable;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.HashMap;
46 import java.util.Iterator;
47 import java.util.Map;
48 import java.util.Map.Entry;
49
50 import javax.servlet.FilterChain;
51 import javax.servlet.ServletException;
52 import javax.servlet.http.HttpServletRequest;
53 import javax.servlet.http.HttpServletResponse;
54
55 import org.apache.commons.collections.MultiMap;
56 import org.apache.commons.collections.map.MultiValueMap;
57 import org.apache.commons.lang.builder.ToStringBuilder;
58 import org.apache.commons.lang.builder.ToStringStyle;
59
60
61
62
63
64
65
66
67
68 public abstract class ContentCachedEntry implements CachedEntry, Serializable {
69
70 private static final ToStringStyle BYTE_ARRAY_SIZE_STYLE = new ToStringStyle() {
71 protected void appendDetail(StringBuffer buffer, String fieldName,
72 byte[] array) {
73 super.appendDetail(buffer, fieldName, array.length + " bytes");
74 }
75 };
76
77 private final String contentType;
78 private final String characterEncoding;
79 private final int statusCode;
80 private transient MultiMap headers;
81 private Map serializableHeadersBackingList;
82 private final long lastModificationTime;
83
84
85
86
87
88
89
90
91
92
93
94 public ContentCachedEntry(String contentType, String characterEncoding, int statusCode, MultiMap headers, long modificationDate) throws IOException {
95 this.contentType = contentType;
96 this.characterEncoding = characterEncoding;
97 this.statusCode = statusCode;
98 this.headers = headers;
99 this.lastModificationTime = modificationDate;
100 }
101
102
103
104
105
106
107
108
109 public String getContentType() {
110 return contentType;
111 }
112
113 public String getCharacterEncoding() {
114 return characterEncoding;
115 }
116
117 public int getStatusCode() {
118 return statusCode;
119 }
120
121 public MultiMap getHeaders() {
122 return headers;
123 }
124
125 public long getLastModificationTime() {
126 return lastModificationTime;
127 }
128
129 public String toString() {
130 return ToStringBuilder.reflectionToString(this, BYTE_ARRAY_SIZE_STYLE);
131 }
132
133
134 private void writeObject(ObjectOutputStream out) throws IOException {
135 serializableHeadersBackingList = new HashMap();
136 Iterator iter = headers.entrySet().iterator();
137 while (iter.hasNext()) {
138 Map.Entry entry = (Entry) iter.next();
139 serializableHeadersBackingList.put(entry.getKey(), new ArrayList((Collection)entry.getValue()));
140 }
141 out.defaultWriteObject();
142 }
143
144 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
145 in.defaultReadObject();
146 headers = new MultiValueMap();
147 Iterator iter = serializableHeadersBackingList.entrySet().iterator();
148 while (iter.hasNext()) {
149 Map.Entry entry = (Entry) iter.next();
150 Collection c = (Collection) entry.getValue();
151 for (Iterator ic = c.iterator(); ic.hasNext();) {
152 headers.put(entry.getKey(), ic.next());
153 }
154 }
155 serializableHeadersBackingList = null;
156 }
157
158 public void replay(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
159 response.setStatus(getStatusCode());
160
161 boolean acceptsGzipEncoding = isAcceptsGzip(request) && canServeGzipContent();
162 addHeaders(acceptsGzipEncoding, response);
163
164
165 response.setContentType(getContentType());
166 response.setCharacterEncoding(getCharacterEncoding());
167
168 writeContent(request, response, chain, acceptsGzipEncoding);
169 }
170
171 protected abstract void writeContent(HttpServletRequest request, HttpServletResponse response, FilterChain chain, boolean acceptsGzipEncoding) throws IOException, ServletException;
172
173
174
175
176 protected void addHeaders(final boolean acceptsGzipEncoding, final HttpServletResponse response) {
177 final MultiMap headers = getHeaders();
178
179 final Iterator it = headers.keySet().iterator();
180 while (it.hasNext()) {
181 final String header = (String) it.next();
182 if (!acceptsGzipEncoding) {
183
184 if ("Content-Encoding".equals(header) || "Vary".equals(header)) {
185 continue;
186 }
187 }
188 if (response.containsHeader(header)) {
189
190 continue;
191 }
192
193 final Collection values = (Collection) headers.get(header);
194 final Iterator valIt = values.iterator();
195 while (valIt.hasNext()) {
196 final Object val = valIt.next();
197 RequestHeaderUtil.setHeader(response, header, val);
198 }
199 }
200
201 if(acceptsGzipEncoding){
202
203 if (!response.containsHeader("Content-Encoding")) {
204 RequestHeaderUtil.addAndVerifyHeader(response, "Content-Encoding", "gzip");
205 RequestHeaderUtil.addAndVerifyHeader(response, "Vary", "Accept-Encoding");
206 }
207 }
208 }
209
210 protected boolean isAcceptsGzip(HttpServletRequest request){
211 return GZipUtil.isAcceptsGzip(request);
212 }
213
214 abstract protected boolean canServeGzipContent();
215
216 }