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.cache.CacheConstants;
37
38 import java.util.ArrayList;
39 import java.util.Date;
40 import java.util.List;
41
42 import org.apache.commons.httpclient.HeaderElement;
43 import org.apache.commons.httpclient.util.DateParseException;
44 import org.apache.commons.httpclient.util.DateUtil;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class ResponseExpirationCalculator {
67
68 private static class HeaderEntry {
69
70 private final String name;
71 private final Object value;
72 private HeaderElement[] elements;
73
74 public HeaderEntry(String name, Object value) {
75 this.name = name;
76 this.value = value;
77 }
78
79 public String getName() {
80 return name;
81 }
82
83 public Object getValue() {
84 return value;
85 }
86
87 public HeaderElement[] getElements() {
88 if (elements == null) {
89 elements = HeaderElement.parseElements(value.toString());
90 }
91 return elements;
92 }
93
94 public String toExternalFormat() {
95 return (name != null ? name : "") + ": " + (value != null ? value : "");
96 }
97
98 @Override
99 public String toString() {
100 return toExternalFormat();
101 }
102 }
103
104 private static final Logger logger = LoggerFactory.getLogger(ResponseExpirationCalculator.class);
105
106 private final List<HeaderEntry> headers = new ArrayList<HeaderEntry>();
107
108 public boolean addHeader(String name, Object value) {
109
110 if (CacheConstants.HEADER_EXPIRES.equals(name)) {
111 this.headers.add(new HeaderEntry(name, value));
112 return true;
113 }
114
115 if (CacheConstants.HEADER_CACHE_CONTROL.equals(name)) {
116 this.headers.add(new HeaderEntry(name, value));
117 return true;
118 }
119
120 if (CacheConstants.HEADER_PRAGMA.equals(name)) {
121 HeaderEntry headerEntry = new HeaderEntry(name, value);
122 if (isHeaderWithElement(headerEntry, CacheConstants.HEADER_PRAGMA, CacheConstants.HEADER_VALUE_NO_CACHE)) {
123 this.headers.add(headerEntry);
124 return true;
125 }
126 }
127
128 return false;
129 }
130
131
132
133
134
135 public int getMaxAgeInSeconds() {
136
137 for (HeaderEntry header : headers) {
138
139
140 if (isHeaderWithElement(header, CacheConstants.HEADER_PRAGMA, CacheConstants.HEADER_VALUE_NO_CACHE)) {
141 return 0;
142 }
143
144
145 if (isHeaderWithElement(header, CacheConstants.HEADER_CACHE_CONTROL, CacheConstants.HEADER_VALUE_NO_CACHE)) {
146 return 0;
147 }
148
149
150 if (isHeaderWithElement(header, CacheConstants.HEADER_CACHE_CONTROL, CacheConstants.HEADER_VALUE_PRIVATE)) {
151 return 0;
152 }
153 }
154
155 int maxAge = -1;
156
157
158
159
160
161 for (HeaderEntry header : headers) {
162 HeaderElement element = getHeaderElement(header, CacheConstants.HEADER_CACHE_CONTROL, CacheConstants.HEADER_VALUE_S_MAXAGE);
163 if (element != null) {
164 try {
165 int n = Integer.parseInt(element.getValue());
166 if (maxAge == -1 || n < maxAge) {
167 maxAge = n;
168 }
169 } catch (NumberFormatException e) {
170 logger.warn("Ignoring unparseable " + CacheConstants.HEADER_CACHE_CONTROL + " header [" + header.toExternalFormat() + "]");
171 }
172 }
173 }
174
175 if (maxAge != -1) {
176 return maxAge;
177 }
178
179
180
181
182 for (HeaderEntry header : headers) {
183 HeaderElement element = getHeaderElement(header, CacheConstants.HEADER_CACHE_CONTROL, CacheConstants.HEADER_VALUE_MAX_AGE);
184 if (element != null) {
185 try {
186 int n = Integer.parseInt(element.getValue());
187 if (maxAge == -1 || n < maxAge) {
188 maxAge = n;
189 }
190 } catch (NumberFormatException e) {
191 logger.warn("Ignoring unparseable " + CacheConstants.HEADER_CACHE_CONTROL + " header [" + header.toExternalFormat() + "]");
192 }
193 }
194 }
195
196 if (maxAge != -1) {
197 return maxAge;
198 }
199
200
201
202 for (HeaderEntry header : headers) {
203 if (CacheConstants.HEADER_EXPIRES.equals(header.getName())) {
204
205 Object value = header.getValue();
206
207 if (value instanceof Integer) {
208
209 int n = (int) ((Integer) value - (System.currentTimeMillis() / 1000L));
210 if (maxAge == -1 || n < maxAge) {
211 maxAge = n;
212 }
213 }
214 if (value instanceof Long) {
215
216 int n = (int) (((Long) value - System.currentTimeMillis()) / 1000L);
217 if (maxAge == -1 || n < maxAge) {
218 maxAge = n;
219 }
220 }
221 if (value instanceof String) {
222 String s = (String) value;
223
224
225 if ("0".equals(s)) {
226 return 0;
227 }
228
229
230 try {
231 Date expires = DateUtil.parseDate(s);
232 int n = (int) (expires.getTime() - System.currentTimeMillis());
233 if (maxAge == -1 || n < maxAge) {
234 maxAge = n;
235 }
236 } catch (DateParseException e) {
237 logger.warn("Ignoring unparseable " + CacheConstants.HEADER_EXPIRES + " header [" + header.toExternalFormat() + "]");
238 }
239 }
240 }
241 }
242
243 return maxAge;
244 }
245
246 private boolean isHeaderWithElement(HeaderEntry header, String headerName, String elementName) {
247 return getHeaderElement(header, headerName, elementName) != null;
248 }
249
250 private HeaderElement getHeaderElement(HeaderEntry header, String headerName, String elementName) {
251 if (headerName.equals(header.getName())) {
252 HeaderElement[] elements = header.getElements();
253 for (HeaderElement element : elements) {
254 if (element.getName().equals(elementName)) {
255 return element;
256 }
257 }
258 }
259 return null;
260 }
261 }