diff --git a/src/qz/auth/CRL.java b/src/qz/auth/CRL.java index 295e74c62..519b7458e 100644 --- a/src/qz/auth/CRL.java +++ b/src/qz/auth/CRL.java @@ -3,10 +3,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import qz.utils.ConnectionUtilities; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.net.URL; import java.util.ArrayList; /** @@ -37,8 +38,7 @@ public static CRL getInstance() { public void run() { log.info("Loading CRL from {}", CRL_URL); - - try(BufferedReader br = new BufferedReader(new InputStreamReader(new URL(CRL_URL).openStream()))) { + try(BufferedReader br = new BufferedReader(new InputStreamReader(ConnectionUtilities.getInputStream(CRL_URL)))) { String line; while((line = br.readLine()) != null) { //Ignore empty and commented lines diff --git a/src/qz/printer/action/PrintImage.java b/src/qz/printer/action/PrintImage.java index 5d72a0ce8..7abe2889b 100644 --- a/src/qz/printer/action/PrintImage.java +++ b/src/qz/printer/action/PrintImage.java @@ -19,6 +19,7 @@ import qz.common.Constants; import qz.printer.PrintOptions; import qz.printer.PrintOutput; +import qz.utils.ConnectionUtilities; import qz.utils.PrintingUtilities; import qz.utils.SystemUtilities; @@ -37,7 +38,6 @@ import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -80,7 +80,7 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce if (flavor == PrintingUtilities.Flavor.BASE64) { bi = ImageIO.read(new ByteArrayInputStream(Base64.decodeBase64(data.getString("data")))); } else { - bi = ImageIO.read(new URL(data.getString("data"))); + bi = ImageIO.read(ConnectionUtilities.getInputStream(data.getString("data"))); } images.add(bi); diff --git a/src/qz/printer/action/PrintPDF.java b/src/qz/printer/action/PrintPDF.java index 8664a275b..ebb48d91e 100644 --- a/src/qz/printer/action/PrintPDF.java +++ b/src/qz/printer/action/PrintPDF.java @@ -20,6 +20,7 @@ import qz.printer.PDFWrapper; import qz.printer.PrintOptions; import qz.printer.PrintOutput; +import qz.utils.ConnectionUtilities; import qz.utils.PrintingUtilities; import qz.utils.SystemUtilities; @@ -34,7 +35,6 @@ import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.*; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -84,7 +84,7 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce if (flavor == PrintingUtilities.Flavor.BASE64) { doc = PDDocument.load(new ByteArrayInputStream(Base64.decodeBase64(data.getString("data")))); } else { - doc = PDDocument.load(new URL(data.getString("data")).openStream()); + doc = PDDocument.load(ConnectionUtilities.getInputStream(data.getString("data"))); } originals.add(doc); diff --git a/src/qz/printer/action/PrintRaw.java b/src/qz/printer/action/PrintRaw.java index e5c8ca891..b4d5ceb4a 100644 --- a/src/qz/printer/action/PrintRaw.java +++ b/src/qz/printer/action/PrintRaw.java @@ -29,6 +29,7 @@ import qz.printer.PrintOptions; import qz.printer.PrintOutput; import qz.utils.ByteUtilities; +import qz.utils.ConnectionUtilities; import qz.utils.FileUtilities; import qz.utils.PrintingUtilities; import qz.utils.ShellUtilities; @@ -43,7 +44,6 @@ import java.awt.image.BufferedImage; import java.io.*; import java.net.Socket; -import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -152,7 +152,7 @@ private ImageWrapper getImageWrapper(String data, JSONObject opt, boolean fromFi BufferedImage bi; if (fromFile) { - bi = ImageIO.read(new URL(data)); + bi = ImageIO.read(ConnectionUtilities.getInputStream(data)); } else { bi = ImageIO.read(new ByteArrayInputStream(Base64.decodeBase64(data))); } @@ -164,7 +164,7 @@ private ImageWrapper getPdfWrapper(String data, JSONObject opt, boolean fromFile PDDocument doc; if (fromFile) { - doc = PDDocument.load(new URL(data).openStream()); + doc = PDDocument.load(ConnectionUtilities.getInputStream(data)); } else { doc = PDDocument.load(new ByteArrayInputStream(Base64.decodeBase64(data))); } diff --git a/src/qz/utils/ConnectionUtilities.java b/src/qz/utils/ConnectionUtilities.java new file mode 100644 index 000000000..27342efd9 --- /dev/null +++ b/src/qz/utils/ConnectionUtilities.java @@ -0,0 +1,89 @@ +/** + * @author Ewan McDougall + * + * Copyright (C) 2017 Tres Finocchiaro, QZ Industries, LLC + * + * LGPL 2.1 This is free software. This software and source code are released under + * the "LGPL 2.1 License". A copy of this license should be distributed with + * this software. http://www.gnu.org/licenses/lgpl-2.1.html + */ +package qz.utils; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.LoggerFactory; +import qz.common.Constants; + +public final class ConnectionUtilities { + + private static final org.slf4j.Logger log = LoggerFactory.getLogger(ConnectionUtilities.class); + private static String userAgent; + + /** + * Returns an input stream that reads from the URL. + * While setting the underlying URLConnections User-Agent. + * + * @param urlString an absolute URL giving location of resource to read. + */ + public static InputStream getInputStream(String urlString) throws IOException { + URLConnection urlConn = new URL(urlString).openConnection(); + urlConn.setRequestProperty("User-Agent", getUserAgent()); + 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.MAJOR_MINOR, + System.getProperty("java.vm.specification.version") + ); + log.debug("User agent string for URL requests: {}", userAgent); + } + return userAgent; + } + + 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; + } + + private static String getOS() { + if (SystemUtilities.isWindows()) { + //assume NT + return String.format("Windows NT %s", System.getProperty("os.version")); + } else if(SystemUtilities.isMac()) { + return String.format("Macintosh; %s %s", System.getProperty("os.name"), System.getProperty("os.version").replace('.', '_')); + } else if(SystemUtilities.isLinux()) { + //detect display manager + String linuxOS = ""; + String[] parts = StringUtils.split(System.getProperty("awt.toolkit"), "."); + //assume sun.awt.X11.XToolKit namespace + if (!GraphicsEnvironment.isHeadless() && parts != null && parts.length > 2) { + linuxOS = parts[2]; + } + if (SystemUtilities.isUbuntu()) { + linuxOS += (linuxOS.isEmpty() ? "" : "; ") + "Ubuntu"; + } else if(SystemUtilities.isFedora()) { + linuxOS += (linuxOS.isEmpty()? "" : "; ") + "Fedora"; + } + return linuxOS; + } + return System.getProperty("os.name"); + } +} diff --git a/src/qz/utils/FileUtilities.java b/src/qz/utils/FileUtilities.java index 1c2bb4bcd..061057fa5 100644 --- a/src/qz/utils/FileUtilities.java +++ b/src/qz/utils/FileUtilities.java @@ -19,11 +19,11 @@ import qz.common.ByteArrayBuilder; import qz.common.Constants; import qz.exception.NullCommandException; +import qz.utils.ConnectionUtilities; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; -import java.net.URL; import java.util.HashMap; @@ -121,7 +121,7 @@ public static String readLocalFile(String file) throws IOException { } public static byte[] readRawFile(String url) throws IOException { - return readFile(new DataInputStream(new URL(url).openStream())); + return readFile(new DataInputStream(ConnectionUtilities.getInputStream(url))); } private static byte[] readFile(DataInputStream in) throws IOException { diff --git a/src/qz/utils/SemVer.java b/src/qz/utils/SemVer.java new file mode 100644 index 000000000..37b5acd09 --- /dev/null +++ b/src/qz/utils/SemVer.java @@ -0,0 +1,30 @@ +package qz.utils; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +public class SemVer { + public String MAJOR; + public String MINOR; + public String PATCH; + public String PRE; + public String FULL; + public String MAJOR_MINOR; + + public SemVer(String version) { + String[] parts = StringUtils.split(version, "."); + String[] pre = StringUtils.split(version, "-"); + FULL = version; + MAJOR = parts.length > 0 ? parts[0] : ""; + MINOR = parts.length > 1 ? parts[1] : ""; + PATCH = parts.length > 2 ? parts[2] : ""; + PRE = pre.length > 1 ? pre[1] : StringUtils.join(ArrayUtils.subarray(parts, 3, parts.length - 1), "."); + MAJOR_MINOR = MAJOR + "." + MINOR; + } + + @Override + public String toString() { + return FULL; + } + +} diff --git a/src/qz/utils/SystemUtilities.java b/src/qz/utils/SystemUtilities.java index 36f2405a0..e11d0aa5f 100644 --- a/src/qz/utils/SystemUtilities.java +++ b/src/qz/utils/SystemUtilities.java @@ -111,6 +111,14 @@ public static String getSharedDirectory() { return parent + File.separator + folder; } + /** + * Detect 32-bit JVM on 64-bit Windows + * @return + */ + public static boolean isWow64() { + String arch = System.getProperty("os.arch"); + return isWindows() && !arch.contains("x86_64") && !arch.contains("amd64") && System.getenv("PROGRAMFILES(x86)") != null; + } /** * Determine if the current Operating System is Windows diff --git a/src/qz/ws/PrintSocketServer.java b/src/qz/ws/PrintSocketServer.java index 1f8970efc..0b6450ec9 100644 --- a/src/qz/ws/PrintSocketServer.java +++ b/src/qz/ws/PrintSocketServer.java @@ -107,6 +107,7 @@ public static void main(String[] args) { setupFileLogging(); try { + log.info("Starting {} {}", Constants.ABOUT_TITLE, Constants.VERSION); SwingUtilities.invokeAndWait(() -> trayManager = new TrayManager(headless)); runServer(); }