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 private String originalUrl;
84 private int timeToLiveInSeconds = -1;
85
86
87
88
89
90
91
92
93
94
95
96 public ContentCachedEntry(String contentType, String characterEncoding, int statusCode, MultiMap headers, long modificationDate, String originalUrl, int timeToLiveInSeconds) throws IOException {
97 this.contentType = contentType;
98 this.characterEncoding = characterEncoding;
99 this.statusCode = statusCode;
100 this.headers = headers;
101 this.lastModificationTime = modificationDate;
102 this.originalUrl = originalUrl;
103 this.timeToLiveInSeconds = timeToLiveInSeconds;
104 }
105
106 public String getOriginalURL() {
107 return this.originalUrl;
108 }
109
110
111
112
113
114
115
116
117 public String getContentType() {
118 return contentType;
119 }
120
121 public String getCharacterEncoding() {
122 return characterEncoding;
123 }
124
125 public int getStatusCode() {
126 return statusCode;
127 }
128
129 public MultiMap getHeaders() {
130 return headers;
131 }
132
133 public long getLastModificationTime() {
134 return lastModificationTime;
135 }
136
137 public int getTimeToLiveInSeconds() {
138 return timeToLiveInSeconds;
139 }
140
141 @Override
142 public String toString() {
143 return ToStringBuilder.reflectionToString(this, BYTE_ARRAY_SIZE_STYLE);
144 }
145
146
147 private void writeObject(ObjectOutputStream out) throws IOException {
148 serializableHeadersBackingList = new HashMap();
149 Iterator iter = headers.entrySet().iterator();
150 while (iter.hasNext()) {
151 Map.Entry entry = (Entry) iter.next();
152 serializableHeadersBackingList.put(entry.getKey(), new ArrayList((Collection)entry.getValue()));
153 }
154 out.defaultWriteObject();
155 }
156
157 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
158 in.defaultReadObject();
159 headers = new MultiValueMap();
160 Iterator iter = serializableHeadersBackingList.entrySet().iterator();
161 while (iter.hasNext()) {
162 Map.Entry entry = (Entry) iter.next();
163 Collection c = (Collection) entry.getValue();
164 for (Iterator ic = c.iterator(); ic.hasNext();) {
165 headers.put(entry.getKey(), ic.next());
166 }
167 }
168 serializableHeadersBackingList = null;
169 }
170
171 public void replay(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
172 response.setStatus(getStatusCode());
173
174 boolean acceptsGzipEncoding = isAcceptsGzip(request) && canServeGzipContent();
175 addHeaders(acceptsGzipEncoding, response);
176
177
178 response.setContentType(getContentType());
179 response.setCharacterEncoding(getCharacterEncoding());
180
181 writeContent(request, response, chain, acceptsGzipEncoding);
182 }
183
184 protected abstract void writeContent(HttpServletRequest request, HttpServletResponse response, FilterChain chain, boolean acceptsGzipEncoding) throws IOException, ServletException;
185
186
187
188
189 protected void addHeaders(final boolean acceptsGzipEncoding, final HttpServletResponse response) {
190 final MultiMap headers = getHeaders();
191
192 final Iterator it = headers.keySet().iterator();
193 while (it.hasNext()) {
194 final String header = (String) it.next();
195 if (!acceptsGzipEncoding) {
196
197 if ("Content-Encoding".equals(header) || "Vary".equals(header)) {
198 continue;
199 }
200 }
201 if (response.containsHeader(header)) {
202
203 continue;
204 }
205
206 final Collection values = (Collection) headers.get(header);
207 final Iterator valIt = values.iterator();
208 while (valIt.hasNext()) {
209 final Object val = valIt.next();
210 RequestHeaderUtil.setHeader(response, header, val);
211 }
212 }
213
214 if(acceptsGzipEncoding){
215
216 if (!response.containsHeader("Content-Encoding")) {
217 RequestHeaderUtil.addAndVerifyHeader(response, "Content-Encoding", "gzip");
218 RequestHeaderUtil.addAndVerifyHeader(response, "Vary", "Accept-Encoding");
219 }
220 }
221 }
222
223 protected boolean isAcceptsGzip(HttpServletRequest request){
224 return GZipUtil.isAcceptsGzip(request);
225 }
226
227 abstract protected boolean canServeGzipContent();
228
229 }