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.executor;
35
36 import info.magnolia.cms.util.RequestHeaderUtil;
37 import info.magnolia.module.cache.Cache;
38 import info.magnolia.module.cache.CachePolicyResult;
39 import info.magnolia.module.cache.filter.CachedEntry;
40 import info.magnolia.module.cache.filter.CachedError;
41 import info.magnolia.module.cache.filter.CachedPage;
42 import info.magnolia.module.cache.filter.CachedRedirect;
43 import info.magnolia.voting.voters.UserAgentVoter;
44
45 import java.io.IOException;
46 import java.util.Collection;
47 import java.util.Iterator;
48
49 import javax.servlet.FilterChain;
50 import javax.servlet.ServletException;
51 import javax.servlet.http.HttpServletRequest;
52 import javax.servlet.http.HttpServletResponse;
53
54 import org.apache.commons.collections.MultiMap;
55
56
57
58
59
60
61
62 public class UseCache extends AbstractExecutor {
63 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UseCache.class);
64
65 public void processCacheRequest(HttpServletRequest request,
66 HttpServletResponse response, FilterChain chain, Cache cache,
67 CachePolicyResult cachePolicy) throws IOException, ServletException {
68 CachedEntry cached = (CachedEntry) cachePolicy.getCachedEntry();
69 processCachedEntry(cached, request, response);
70 }
71
72 protected void processCachedEntry(CachedEntry cached, HttpServletRequest request, HttpServletResponse response) throws IOException {
73 log.debug("Serving {}", cached);
74 if (cached instanceof CachedPage) {
75 final CachedPage page = (CachedPage) cached;
76 if (!ifModifiedSince(request, page.getLastModificationTime())) {
77 if (response.isCommitted() && page.getPreCacheStatusCode() != HttpServletResponse.SC_NOT_MODIFIED) {
78
79 log.warn("Unable to change status on already commited response {}.", response.getClass().getName());
80 } else {
81
82 page.setPreCacheStatusCode(0);
83 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
84 return;
85 }
86 }
87
88 writePage(request, response, page);
89 response.flushBuffer();
90 } else if (cached instanceof CachedError) {
91 final CachedError error = (CachedError) cached;
92 if (!response.isCommitted()) {
93 response.sendError(error.getStatusCode());
94 } else {
95
96
97 log.debug("Failed to serve cached error due to response already committed.");
98 }
99 } else if (cached instanceof CachedRedirect) {
100 final CachedRedirect redir = (CachedRedirect) cached;
101
102
103 if (!response.isCommitted()) {
104 response.sendRedirect(redir.getLocation());
105 }
106 } else if (cached == null) {
107
108 return;
109 } else {
110 throw new IllegalStateException("Unexpected CachedEntry type: " + cached);
111 }
112 }
113
114 protected void writePage(final HttpServletRequest request, final HttpServletResponse response, final CachedPage cachedEntry) throws IOException {
115 int vote = getCompressionVote(request, UserAgentVoter.class);
116 log.debug("On user agent {} voted {} ", request.getHeader("User-Agent"), "" + vote);
117
118 final boolean acceptsGzipEncoding = vote == 0 && RequestHeaderUtil.acceptsGzipEncoding(request) && cachedEntry.getUngzippedContent() != null;
119 log.debug("Accepts gzip encoding: {}", "" + acceptsGzipEncoding);
120
121 response.setStatus(cachedEntry.getStatusCode());
122 addHeaders(cachedEntry, acceptsGzipEncoding, response);
123
124
125 response.setContentType(cachedEntry.getContentType());
126 response.setCharacterEncoding(cachedEntry.getCharacterEncoding());
127 writeContent(response, cachedEntry, acceptsGzipEncoding);
128 }
129
130
131
132
133 protected void addHeaders(final CachedPage cachedEntry, final boolean acceptsGzipEncoding, final HttpServletResponse response) {
134 final MultiMap headers = cachedEntry.getHeaders();
135
136 final Iterator it = headers.keySet().iterator();
137 while (it.hasNext()) {
138 final String header = (String) it.next();
139 if (!acceptsGzipEncoding) {
140
141 if ("Content-Encoding".equals(header) || "Vary".equals(header)) {
142 continue;
143 }
144 }
145 if (response.containsHeader(header)) {
146
147 continue;
148 }
149
150 final Collection values = (Collection) headers.get(header);
151 final Iterator valIt = values.iterator();
152 while (valIt.hasNext()) {
153 final Object val = valIt.next();
154 if (val instanceof Long) {
155 response.addDateHeader(header, ((Long) val).longValue());
156 } else if (val instanceof Integer) {
157 response.addIntHeader(header, ((Integer) val).intValue());
158 } else if (val instanceof String) {
159 response.addHeader(header, (String) val);
160 } else {
161 throw new IllegalStateException("Unrecognized type for header [" + header + "], value is: " + val);
162 }
163
164 }
165 }
166 }
167
168 protected void writeContent(final HttpServletResponse response, final CachedPage cachedEntry, boolean acceptsGzipEncoding) throws IOException {
169 final byte[] body;
170 if (!acceptsGzipEncoding ) {
171 if (cachedEntry.getUngzippedContent() != null) {
172
173 body = cachedEntry.getUngzippedContent();
174 } else {
175
176 body = cachedEntry.getDefaultContent();
177 }
178 } else {
179
180 body = cachedEntry.getDefaultContent();
181
182 if (!response.isCommitted() && !response.containsHeader("Content-Encoding")) {
183 RequestHeaderUtil.addAndVerifyHeader(response, "Content-Encoding", "gzip");
184 RequestHeaderUtil.addAndVerifyHeader(response, "Vary", "Accept-Encoding");
185 }
186 }
187
188
189
190
191
192
193
194 response.setContentLength(body.length);
195 response.getOutputStream().write(body);
196 }
197
198 }