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