blob: 81cf589a12e03b916c3bb214daf0733d2b784aa8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.tobago.context;
import org.apache.myfaces.tobago.internal.util.Deprecation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.StringTokenizer;
public final class UserAgent implements Serializable {
public static final String DEFAULT_NAME = "standard";
public static final UserAgent DEFAULT = new UserAgent(null, null);
public static final UserAgent MSIE = new UserAgent("msie", null);
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MSIE_5_0 = new UserAgent("msie", "5_0");
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MSIE_5_5 = new UserAgent("msie", "5_5");
public static final UserAgent MSIE_6_0 = new UserAgent(
"msie", "6_0", EnumSet.noneOf(Capability.class), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
public static final UserAgent MSIE_7_0 = new UserAgent(
"msie", "7_0", EnumSet.noneOf(Capability.class), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
public static final UserAgent MSIE_7_0_COMPAT = new UserAgent(
"msie", "7_0", EnumSet.of(Capability.IE_COMPATIBILITY_MODE), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
/**
* @deprecated no longer supported, since Tobago 1.5. Misspelled. Use {@link #MSIE_7_0}
*/
@Deprecated
public static final UserAgent MSIE_7_O = MSIE_7_0;
public static final UserAgent MSIE_8_0 = new UserAgent(
"msie", "8_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
public static final UserAgent MSIE_9_0 = new UserAgent(
"msie", "9_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
// CSP is not fully supported, only sandboxing
public static final UserAgent MSIE_10_0 = new UserAgent(
"msie", "10_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
// CSP is not fully supported, only sandboxing
public static final UserAgent MSIE_11_0 = new UserAgent(
"msie", "11_0", EnumSet.of(Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MSIE_5_0_MAC = new UserAgent("msie", "5_0_mac");
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MSIE_6_0_MAC = new UserAgent("msie", "6_0_mac");
/**
* e. g. Opera 10
*/
public static final UserAgent PRESTO = new UserAgent("presto", null, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
/**
* @deprecated no longer supported, since Tobago 1.5. Please use {@link #PRESTO}.
*/
@Deprecated
public static final UserAgent OPERA = new UserAgent("opera", null);
/**
* @deprecated no longer supported, since Tobago 1.5. Please use {@link #PRESTO}.
*/
@Deprecated
public static final UserAgent OPERA_5_0 = new UserAgent("opera", "5_0");
/**
* @deprecated no longer supported, since Tobago 1.5. Please use {@link #PRESTO}.
*/
@Deprecated
public static final UserAgent OPERA_6_0 = new UserAgent("opera", "6_0");
/**
* @deprecated no longer supported, since Tobago 1.5. Please use {@link #PRESTO}.
*/
@Deprecated
public static final UserAgent OPERA_7_11 = new UserAgent("opera", "7_11");
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MOZILLA = new UserAgent("mozilla", null);
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MOZILLA_4_7 = new UserAgent("mozilla", "4_7");
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MOZILLA_5_0 = new UserAgent("mozilla", "5_0");
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static final UserAgent MOZILLA_5_0_R1_6 = new UserAgent("mozilla", "5_0_r1_6");
/**
* e. g. Firefox
*/
public static final UserAgent GECKO = new UserAgent("gecko", null, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
/**
* e. g. Firefox 2.0
*/
public static final UserAgent GECKO_1_8 = new UserAgent("gecko", "1_8", EnumSet.of(Capability.CONTENT_TYPE_XHTML),
CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
/**
* e. g. Firefox 3.0, 3.5, 3.6
*/
public static final UserAgent GECKO_1_9 = new UserAgent("gecko", "1_9", EnumSet.of(Capability.CONTENT_TYPE_XHTML),
CspHeader.NOT_SUPPORTED, CsproHeader.NOT_SUPPORTED);
/**
* e. g. Firefox 4 to 22
*/
public static final UserAgent GECKO_2_0
= new UserAgent("gecko", null,
EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.X, CsproHeader.X);
/**
* e. g. Firefox 23 or higher
*/
public static final UserAgent GECKO_23_0
= new UserAgent("gecko", null,
EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.STANDARD, CsproHeader.STANDARD);
/**
* e. g. Safari 4, Safari 5, Chrome
*/
public static final UserAgent WEBKIT
= new UserAgent("webkit", null,
EnumSet.of(Capability.PLACEHOLDER, Capability.CONTENT_TYPE_XHTML), CspHeader.WEBKIT, CsproHeader.WEBKIT);
private static final long serialVersionUID = 2L;
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final String name;
/**
* @deprecated Version shouldn't be used in the future. Use capability instead, even better
* use same code on the server when possible and use capability via JavaScript.
*/
@Deprecated
private final String version;
private final EnumSet<Capability> capabilities;
private final CspHeader cspHeader;
private final CsproHeader csproHeader;
private UserAgent(final String name, final String version) {
this(name, version, EnumSet.of(Capability.CONTENT_TYPE_XHTML));
}
private UserAgent(final String name, final String version, final EnumSet<Capability> capabilities) {
this(name, version, capabilities, CspHeader.STANDARD, CsproHeader.STANDARD);
}
private UserAgent(
final String name, final String version, final EnumSet<Capability> capabilities, final CspHeader cspHeader,
final CsproHeader csproHeader) {
this.name = name;
this.version = version;
this.capabilities = capabilities;
this.cspHeader = cspHeader;
this.csproHeader = csproHeader;
}
public boolean hasCapability(final Capability capability) {
return capabilities.contains(capability);
}
public boolean isMsie() {
return MSIE.name.equals(name);
}
/**
* @deprecated no longer supported, since Tobago 3.0
*/
@Deprecated
public boolean isMsie6() {
return MSIE_6_0.name.equals(name) && MSIE_6_0.version.equals(version);
}
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public boolean isMozilla() {
return MOZILLA.name.equals(name);
}
public List<String> getFallbackList() {
return getFallbackList(false);
}
private List<String> getFallbackList(final boolean reverseOrder) {
final List<String> list = new ArrayList<>(3);
if (version != null) {
list.add(name + '_' + version);
}
if (name != null) {
list.add(name);
}
list.add(DEFAULT_NAME);
if (reverseOrder) {
Collections.reverse(list);
}
return list;
}
/**
* @return The HTTP header names for Content-Security-Policy.
*/
public String[] getCspHeaders() {
return cspHeader.getNames();
}
/**
* @return The HTTP header name for Content-Security-Policy-Report-Only.
*/
public String[] getCspReportOnlyHeaders() {
return csproHeader.getNames();
}
public static UserAgent getInstance(final String header) {
if (header == null) {
return DEFAULT;
}
if (header.contains("MSIE") || header.contains("Trident")) {
if (header.contains("MSIE 6.0")) {
return MSIE_6_0;
} else if (header.contains("MSIE 7.0")) {
if (header.contains("Trident")) {
return MSIE_7_0_COMPAT;
} else {
return MSIE_7_0;
}
} else if (header.contains("MSIE 8.0")) {
return MSIE_8_0;
} else if (header.contains("MSIE 9.0")) {
return MSIE_9_0;
} else if (header.contains("MSIE 10.0")) {
return MSIE_10_0;
} else if (header.contains("rv:11")) {
return MSIE_11_0;
} else {
return MSIE;
}
} else if (header.contains("AppleWebKit")) {
return WEBKIT;
} else if (header.contains("Gecko")) {
if (header.contains("rv:1.8")) {
return GECKO_1_8;
} else if (header.contains("rv:1.9")) {
return GECKO_1_9;
} else {
final int index = header.indexOf("rv:");
final StringTokenizer tokenizer = new StringTokenizer(header.substring(index + 3), " .");
final String versionString = tokenizer.nextToken();
try {
final int version = Integer.parseInt(versionString);
if (version >= 23) {
return GECKO_23_0;
} else if (version >= 2) {
return GECKO_2_0;
}
} catch (final NumberFormatException e) {
if (LOG.isDebugEnabled()) {
LOG.debug(header, e);
}
}
return GECKO;
}
} else if (header.contains("Presto")) {
return PRESTO;
}
return DEFAULT;
}
/**
* @deprecated no longer supported, since Tobago 1.5
*/
@Deprecated
public static UserAgent getInstanceForId(final String id) {
Deprecation.LOG.error("Getting the user agent from its id is no longer supported! id='" + id + "'");
return DEFAULT;
}
/**
* @deprecated don't use toString() functionality, but for logging!
*/
@Deprecated
public String toString() {
return version != null
? name + '_' + version
: name;
}
private enum CspHeader {
NOT_SUPPORTED(new String[] {}),
X(new String[] {"Content-Security-Policy", "X-Content-Security-Policy"}),
WEBKIT(new String[] {"Content-Security-Policy", "X-WebKit-CSP"}),
STANDARD(new String[] {"Content-Security-Policy"});
private String[] names;
CspHeader(final String[] names) {
this.names = names;
}
public String[] getNames() {
return names;
}
}
private enum CsproHeader {
NOT_SUPPORTED(new String[] {}),
X(new String[] {"Content-Security-Policy-Report-Only", "X-Content-Security-Policy-Report-Only"}),
WEBKIT(new String[] {"Content-Security-Policy-Report-Only", "X-WebKit-CSP-Report-Only"}),
STANDARD(new String[] {"Content-Security-Policy-Report-Only"});
private String[] names;
CsproHeader(final String[] names) {
this.names = names;
}
public String[] getNames() {
return names;
}
}
}