2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
6 package com.threerings.getdown.launcher;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.io.PrintStream;
12 import java.net.Authenticator;
13 import java.net.HttpURLConnection;
14 import java.net.InetSocketAddress;
15 import java.net.PasswordAuthentication;
16 import java.net.Proxy;
18 import java.net.URLConnection;
19 import java.util.Iterator;
20 import java.util.ServiceLoader;
22 import ca.beq.util.win32.registry.RegistryKey;
23 import ca.beq.util.win32.registry.RegistryValue;
24 import ca.beq.util.win32.registry.RootKey;
26 import com.threerings.getdown.data.Application;
27 import com.threerings.getdown.spi.ProxyAuth;
28 import com.threerings.getdown.util.Config;
29 import com.threerings.getdown.util.ConnectionUtil;
30 import com.threerings.getdown.util.LaunchUtil;
31 import com.threerings.getdown.util.StringUtil;
33 import static com.threerings.getdown.Log.log;
35 public class ProxyUtil {
37 public static boolean autoDetectProxy (Application app)
39 String host = null, port = null;
41 // check for a proxy configured via system properties
42 if (System.getProperty("https.proxyHost") != null) {
43 host = System.getProperty("https.proxyHost");
44 port = System.getProperty("https.proxyPort");
46 if (StringUtil.isBlank(host) && System.getProperty("http.proxyHost") != null) {
47 host = System.getProperty("http.proxyHost");
48 port = System.getProperty("http.proxyPort");
51 // check the Windows registry
52 if (StringUtil.isBlank(host) && LaunchUtil.isWindows()) {
54 String rhost = null, rport = null;
55 boolean enabled = false;
56 RegistryKey.initialize();
57 RegistryKey r = new RegistryKey(RootKey.HKEY_CURRENT_USER, PROXY_REGISTRY);
58 for (Iterator<?> iter = r.values(); iter.hasNext(); ) {
59 RegistryValue value = (RegistryValue)iter.next();
60 if (value.getName().equals("ProxyEnable")) {
61 enabled = value.getStringValue().equals("1");
63 if (value.getName().equals("ProxyServer")) {
64 String strval = value.getStringValue();
65 int cidx = strval.indexOf(":");
67 rport = strval.substring(cidx+1);
68 strval = strval.substring(0, cidx);
77 log.info("Detected no proxy settings in the registry.");
79 } catch (Throwable t) {
80 log.info("Failed to find proxy settings in Windows registry", "error", t);
84 // look for a proxy.txt file
85 if (StringUtil.isBlank(host)) {
86 String[] hostPort = loadProxy(app);
91 if (StringUtil.isBlank(host)) {
95 // yay, we found a proxy configuration, configure it in the app
96 initProxy(app, host, port, null, null);
100 public static boolean canLoadWithoutProxy (URL rurl)
102 log.info("Testing whether proxy is needed, via: " + rurl);
104 // try to make a HEAD request for this URL (use short connect and read timeouts)
105 URLConnection conn = ConnectionUtil.open(Proxy.NO_PROXY, rurl, 5, 5);
106 if (conn instanceof HttpURLConnection) {
107 HttpURLConnection hcon = (HttpURLConnection)conn;
109 hcon.setRequestMethod("HEAD");
111 // make sure we got a satisfactory response code
112 int rcode = hcon.getResponseCode();
113 if (rcode == HttpURLConnection.HTTP_PROXY_AUTH ||
114 rcode == HttpURLConnection.HTTP_FORBIDDEN) {
115 log.warning("Got an 'HTTP credentials needed' response", "code", rcode);
123 // if the appbase is not an HTTP/S URL (like file:), then we don't need a proxy
126 } catch (IOException ioe) {
127 log.info("Failed to HEAD " + rurl + ": " + ioe);
128 log.info("We probably need a proxy, but auto-detection failed.");
133 public static void configProxy (Application app, String host, String port,
134 String username, String password) {
135 // save our proxy host and port in a local file
136 saveProxy(app, host, port);
138 // save our credentials via the SPI
139 if (!StringUtil.isBlank(username) && !StringUtil.isBlank(password)) {
140 ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
141 Iterator<ProxyAuth> iterator = loader.iterator();
142 String appDir = app.getAppDir().getAbsolutePath();
143 while (iterator.hasNext()) {
144 iterator.next().saveCredentials(appDir, username, password);
148 // also configure them in the app
149 initProxy(app, host, port, username, password);
152 public static String[] loadProxy (Application app) {
153 File pfile = app.getLocalPath("proxy.txt");
154 if (pfile.exists()) {
156 Config pconf = Config.parseConfig(pfile, Config.createOpts(false));
157 return new String[] { pconf.getString("host"), pconf.getString("port") };
158 } catch (IOException ioe) {
159 log.warning("Failed to read '" + pfile + "': " + ioe);
162 return new String[] { null, null};
165 public static void saveProxy (Application app, String host, String port) {
166 File pfile = app.getLocalPath("proxy.txt");
167 try (PrintStream pout = new PrintStream(new FileOutputStream(pfile))) {
168 if (!StringUtil.isBlank(host)) {
169 pout.println("host = " + host);
171 if (!StringUtil.isBlank(port)) {
172 pout.println("port = " + port);
174 } catch (IOException ioe) {
175 log.warning("Error creating proxy file '" + pfile + "': " + ioe);
179 public static void initProxy (Application app, String host, String port,
180 String username, String password)
182 // check whether we have saved proxy credentials
183 String appDir = app.getAppDir().getAbsolutePath();
184 ServiceLoader<ProxyAuth> loader = ServiceLoader.load(ProxyAuth.class);
185 Iterator<ProxyAuth> iter = loader.iterator();
186 ProxyAuth.Credentials creds = iter.hasNext() ? iter.next().loadCredentials(appDir) : null;
188 username = creds.username;
189 password = creds.password;
191 boolean haveCreds = !StringUtil.isBlank(username) && !StringUtil.isBlank(password);
193 int pport = StringUtil.isBlank(port) ? 80 : Integer.valueOf(port);
194 log.info("Using proxy", "host", host, "port", pport, "haveCreds", haveCreds);
195 app.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, pport));
198 final String fuser = username;
199 final char[] fpass = password.toCharArray();
200 Authenticator.setDefault(new Authenticator() {
201 @Override protected PasswordAuthentication getPasswordAuthentication () {
202 return new PasswordAuthentication(fuser, fpass);
208 protected static final String PROXY_REGISTRY =
209 "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";