| /* |
| * 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; |
| } |
| } |
| } |