From 204e2cba716727b75678ea48f43a6b5263106123 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Tue, 26 May 2020 15:57:28 -0400 Subject: [PATCH] Add Client Hints support (#643) Add Sec-CH-UA* request headers in favor of legacy User-Agent string Closes #552 --- src/qz/utils/ConnectionUtilities.java | 109 ++++++++++++++++++++------ 1 file changed, 83 insertions(+), 26 deletions(-) diff --git a/src/qz/utils/ConnectionUtilities.java b/src/qz/utils/ConnectionUtilities.java index 1372275d8..e1b3bf1a3 100644 --- a/src/qz/utils/ConnectionUtilities.java +++ b/src/qz/utils/ConnectionUtilities.java @@ -14,6 +14,8 @@ import java.io.InputStream; import java.net.URL; import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.lang3.StringUtils; @@ -23,7 +25,7 @@ public final class ConnectionUtilities { private static final org.slf4j.Logger log = LoggerFactory.getLogger(ConnectionUtilities.class); - private static String userAgent; + private static Map requestProps; /** * Returns an input stream that reads from the URL. @@ -33,42 +35,60 @@ public final class ConnectionUtilities { */ public static InputStream getInputStream(String urlString) throws IOException { URLConnection urlConn = new URL(urlString).openConnection(); - urlConn.setRequestProperty("User-Agent", getUserAgent()); + for( String key : getRequestProperties().keySet()) { + urlConn.setRequestProperty(key, requestProps.get(key)); + } return urlConn.getInputStream(); } - private static String getUserAgent() { - if (userAgent == null) { - //mozilla 5.0 compat - userAgent = String.format("Mozilla/5.0 (%s; %s) %s/%s Java/%s", - getOS(), - getArch(), - Constants.ABOUT_TITLE.replaceAll("[^a-zA-Z]", ""), - Constants.VERSION.getNormalVersion(), - System.getProperty("java.vm.specification.version") - ); - log.debug("User agent string for URL requests: {}", userAgent); + private static Map getRequestProperties() { + if (requestProps == null) { + requestProps = new HashMap() { + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String key : keySet()) + sb.append(key + ": " + get(key) + "\n"); + return sb.toString(); + } + }; + + // Legacy User-Agent String + requestProps.put("User-Agent", String.format("Mozilla/5.0 (%s; %s) %s/%s %s/%s", + getUserAgentOS(), + getUserAgentArch(), + Constants.ABOUT_TITLE.replaceAll("[^a-zA-Z]", ""), + Constants.VERSION.getNormalVersion(), + getFrameworkName(), + getFrameworkMajorVersion() + + )); + + // Client Hints + requestProps.put("Sec-CH-UA-Platform", getPlatform(false)); + requestProps.put("Sec-CH-UA-Platform-Version", getPlatformVersion()); + requestProps.put("Sec-CH-UA-Arch", getArch()); + requestProps.put("Sec-CH-UA-Full-Version", Constants.VERSION.toString()); + requestProps.put("Sec-CH-UA", String.format("\"%s\"; v=\"%s\", \"%s\"; v=\"%s\"", + Constants.ABOUT_TITLE, + Constants.VERSION, + getFrameworkName(), + getFrameworkVersion())); + log.trace("User agent string for URL requests:\n\n{}", requestProps.toString()); } - return userAgent; + return requestProps; } private static String getArch() { String arch = System.getProperty("os.arch"); - arch = "amd64".equalsIgnoreCase(arch) ? "x86_64" : arch; - if (SystemUtilities.isWow64()) { - return "WOW64"; - } else if(SystemUtilities.isLinux()) { - return "Linux " + arch; - } - return arch; + return "amd64".equalsIgnoreCase(arch) ? "x86_64" : arch; } - private static String getOS() { - if (SystemUtilities.isWindows()) { - //assume NT - return String.format("Windows NT %s", System.getProperty("os.version")); + private static String getPlatform(boolean legacy) { + if(SystemUtilities.isWindows()) { + return legacy ? "Windows NT" : "Windows"; } else if(SystemUtilities.isMac()) { - return String.format("Macintosh; %s %s", System.getProperty("os.name"), System.getProperty("os.version").replace('.', '_')); + return legacy ? "Macintosh" : "macOS"; } else if(SystemUtilities.isLinux()) { //detect display manager String linuxOS = ""; @@ -86,4 +106,41 @@ private static String getOS() { } return System.getProperty("os.name"); } + + private static String getPlatformVersion() { + return System.getProperty("os.version"); + } + + private static String getFrameworkName() { + return "Java"; + } + + private static String getFrameworkMajorVersion() { + return System.getProperty("java.vm.specification.version"); + } + + private static String getFrameworkVersion() { + return Constants.JAVA_VERSION.toString(); + } + + private static String getUserAgentOS() { + if (SystemUtilities.isWindows()) { + //assume NT + return String.format("%s %s", getPlatform(true), getPlatformVersion()); + } else if(SystemUtilities.isMac()) { + return String.format("%s; %s %s", getPlatform(true), System.getProperty("os.name"), getPlatformVersion().replace('.', '_')); + } + return getPlatform(true); + } + + private static String getUserAgentArch() { + String arch = System.getProperty("os.arch"); + arch = "amd64".equalsIgnoreCase(arch) ? "x86_64" : arch; + if (SystemUtilities.isWow64()) { + return "WOW64"; + } else if(SystemUtilities.isLinux()) { + return "Linux " + arch; + } + return arch; + } }