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