1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.context;
21
22 import org.apache.myfaces.tobago.internal.util.Deprecation;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import java.io.Serializable;
27 import java.lang.invoke.MethodHandles;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.EnumSet;
31 import java.util.List;
32 import java.util.StringTokenizer;
33
34 public final class UserAgent implements Serializable {
35
36 public static final String DEFAULT_NAME = "standard";
37
38 public static final UserAgent DEFAULT = new UserAgent(null, null);
39
40 public static final UserAgent MSIE = new UserAgent("msie", null);
41
42
43
44
45 @Deprecated
46 public static final UserAgent MSIE_5_0 = new UserAgent("msie", "5_0");
47
48
49
50
51 @Deprecated
52 public static final UserAgent MSIE_5_5 = new UserAgent("msie", "5_5");
53
54 public static final UserAgent MSIE_6_0 = new UserAgent(
55 "msie", "6_0", EnumSet.noneOf(Capability.class), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
56
57 public static final UserAgent MSIE_7_0 = new UserAgent(
58 "msie", "7_0", EnumSet.noneOf(Capability.class), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
59
60 public static final UserAgent MSIE_7_0_COMPAT = new UserAgent(
61 "msie", "7_0", EnumSet.of(Capability.IE_COMPATIBILITY_MODE), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
62
63
64
65
66 @Deprecated
67 public static final UserAgent MSIE_7_O = MSIE_7_0;
68
69 public static final UserAgent MSIE_8_0 = new UserAgent(
70 "msie", "8_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
71
72 public static final UserAgent MSIE_9_0 = new UserAgent(
73 "msie", "9_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
74
75
76 public static final UserAgent MSIE_10_0 = new UserAgent(
77 "msie", "10_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
78
79
80 public static final UserAgent MSIE_11_0 = new UserAgent(
81 "msie", "11_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
82
83
84
85
86 @Deprecated
87 public static final UserAgent MSIE_5_0_MAC = new UserAgent("msie", "5_0_mac");
88
89
90
91
92 @Deprecated
93 public static final UserAgent MSIE_6_0_MAC = new UserAgent("msie", "6_0_mac");
94
95
96
97
98
99 public static final UserAgent PRESTO = new UserAgent("presto", null, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
100
101
102
103
104 @Deprecated
105 public static final UserAgent OPERA = new UserAgent("opera", null);
106
107
108
109
110 @Deprecated
111 public static final UserAgent OPERA_5_0 = new UserAgent("opera", "5_0");
112
113
114
115
116 @Deprecated
117 public static final UserAgent OPERA_6_0 = new UserAgent("opera", "6_0");
118
119
120
121
122 @Deprecated
123 public static final UserAgent OPERA_7_11 = new UserAgent("opera", "7_11");
124
125
126
127
128 @Deprecated
129 public static final UserAgent MOZILLA = new UserAgent("mozilla", null);
130
131
132
133
134 @Deprecated
135 public static final UserAgent MOZILLA_4_7 = new UserAgent("mozilla", "4_7");
136
137
138
139
140 @Deprecated
141 public static final UserAgent MOZILLA_5_0 = new UserAgent("mozilla", "5_0");
142
143
144
145
146 @Deprecated
147 public static final UserAgent MOZILLA_5_0_R1_6 = new UserAgent("mozilla", "5_0_r1_6");
148
149
150
151
152 public static final UserAgent GECKO = new UserAgent("gecko", null, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
153
154
155
156
157 public static final UserAgent GECKO_1_8 = new UserAgent("gecko", "1_8", EnumSet.of(Capability.CONTENT_TYPE_XHTML),
158 CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
159
160
161
162
163 public static final UserAgent GECKO_1_9 = new UserAgent("gecko", "1_9", EnumSet.of(Capability.CONTENT_TYPE_XHTML),
164 CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
165
166
167
168
169 public static final UserAgent GECKO_2_0
170 = new UserAgent("gecko", null,
171 EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
172
173
174
175
176 public static final UserAgent GECKO_23_0
177 = new UserAgent("gecko", null,
178 EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.STANDARD, CsproHeader.STANDARD);
179
180
181
182
183 public static final UserAgent WEBKIT
184 = new UserAgent("webkit", null,
185 EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.WEBKIT, CsproHeader.WEBKIT);
186
187 private static final long serialVersionUID = 2L;
188
189 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
190
191 private final String name;
192
193
194
195
196
197 @Deprecated
198 private final String version;
199
200 private final EnumSet<Capability> capabilities;
201
202 private final CspHeader cspHeader;
203
204 private final CsproHeader csproHeader;
205
206 private UserAgent(final String name, final String version) {
207 this(name, version, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
208 }
209
210 private UserAgent(final String name, final String version, final EnumSet<Capability> capabilities) {
211 this(name, version, capabilities, CspHeader.STANDARD, CsproHeader.STANDARD);
212 }
213
214 private UserAgent(
215 final String name, final String version, final EnumSet<Capability> capabilities, final CspHeader cspHeader,
216 final CsproHeader csproHeader) {
217 this.name = name;
218 this.version = version;
219 this.capabilities = capabilities;
220 this.cspHeader = cspHeader;
221 this.csproHeader = csproHeader;
222 }
223
224 public boolean hasCapability(final Capability capability) {
225 return capabilities.contains(capability);
226 }
227
228 public boolean isMsie() {
229 return MSIE.name.equals(name);
230 }
231
232
233
234
235 @Deprecated
236 public boolean isMsie6() {
237 return MSIE_6_0.name.equals(name) && MSIE_6_0.version.equals(version);
238 }
239
240
241
242
243 @Deprecated
244 public boolean isMozilla() {
245 return MOZILLA.name.equals(name);
246 }
247
248 public List<String> getFallbackList() {
249 return getFallbackList(false);
250 }
251
252 private List<String> getFallbackList(final boolean reverseOrder) {
253 final List<String> list = new ArrayList<>(3);
254 if (version != null) {
255 list.add(name + '_' + version);
256 }
257 if (name != null) {
258 list.add(name);
259 }
260 list.add(DEFAULT_NAME);
261 if (reverseOrder) {
262 Collections.reverse(list);
263 }
264 return list;
265 }
266
267
268
269
270 public String[] getCspHeaders() {
271 return cspHeader.getNames();
272 }
273
274
275
276
277 public String[] getCspReportOnlyHeaders() {
278 return csproHeader.getNames();
279 }
280
281 public static UserAgent getInstance(final String header) {
282 if (header == null) {
283 return DEFAULT;
284 }
285
286 if (header.contains("MSIE") || header.contains("Trident")) {
287 if (header.contains("MSIE 6.0")) {
288 return MSIE_6_0;
289 } else if (header.contains("MSIE 7.0")) {
290 if (header.contains("Trident")) {
291 return MSIE_7_0_COMPAT;
292 } else {
293 return MSIE_7_0;
294 }
295 } else if (header.contains("MSIE 8.0")) {
296 return MSIE_8_0;
297 } else if (header.contains("MSIE 9.0")) {
298 return MSIE_9_0;
299 } else if (header.contains("MSIE 10.0")) {
300 return MSIE_10_0;
301 } else if (header.contains("rv:11")) {
302 return MSIE_11_0;
303 } else {
304 return MSIE;
305 }
306 } else if (header.contains("AppleWebKit")) {
307 return WEBKIT;
308 } else if (header.contains("Gecko")) {
309 if (header.contains("rv:1.8")) {
310 return GECKO_1_8;
311 } else if (header.contains("rv:1.9")) {
312 return GECKO_1_9;
313 } else {
314 final int index = header.indexOf("rv:");
315 final StringTokenizer tokenizer = new StringTokenizer(header.substring(index + 3), " .");
316 final String versionString = tokenizer.nextToken();
317 try {
318 final int version = Integer.parseInt(versionString);
319 if (version >= 23) {
320 return GECKO_23_0;
321 } else if (version >= 2) {
322 return GECKO_2_0;
323 }
324 } catch (final NumberFormatException e) {
325 if (LOG.isDebugEnabled()) {
326 LOG.debug(header, e);
327 }
328 }
329 return GECKO;
330 }
331 } else if (header.contains("Presto")) {
332 return PRESTO;
333 }
334
335 return DEFAULT;
336 }
337
338
339
340
341 @Deprecated
342 public static UserAgent getInstanceForId(final String id) {
343 Deprecation.LOG.error("Getting the user agent from its id is no longer supported! id='" + id + "'");
344 return DEFAULT;
345 }
346
347
348
349
350 @Deprecated
351 public String toString() {
352 return version != null
353 ? name + '_' + version
354 : name;
355 }
356
357 private enum CspHeader {
358
359 NOT_SUPPORTED(new String[] {}),
360 X(new String[] {"Content-Security-Policy", "X-Content-Security-Policy"}),
361 WEBKIT(new String[] {"Content-Security-Policy", "X-WebKit-CSP"}),
362 STANDARD(new String[] {"Content-Security-Policy"});
363
364 private String[] names;
365
366 CspHeader(final String[] names) {
367 this.names = names;
368 }
369
370 public String[] getNames() {
371 return names;
372 }
373 }
374
375 private enum CsproHeader {
376
377 NOT_SUPPORTED(new String[] {}),
378 X(new String[] {"Content-Security-Policy-Report-Only", "X-Content-Security-Policy-Report-Only"}),
379 WEBKIT(new String[] {"Content-Security-Policy-Report-Only", "X-WebKit-CSP-Report-Only"}),
380 STANDARD(new String[] {"Content-Security-Policy-Report-Only"});
381
382 private String[] names;
383
384 CsproHeader(final String[] names) {
385 this.names = names;
386 }
387
388 public String[] getNames() {
389 return names;
390 }
391 }
392 }