Merge branch 'improvement/JAL-4409_implement_extra_schemes_in_getdown' into develop
[jalview.git] / src / jalview / util / HttpUtils.java
index 5438d4e..44880a0 100644 (file)
@@ -23,15 +23,41 @@ package jalview.util;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
 import java.net.ProtocolException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
-
-import javax.ws.rs.HttpMethod;
-
-import jalview.bin.Cache;
+import java.net.URLConnection;
 
 public class HttpUtils
 {
+  public final static String JALVIEWSCHEMEPREFIX = "jalview";
+
+  public static boolean isPlausibleUri(String s)
+  {
+    if (s == null)
+    {
+      return false;
+    }
+    if (startsWithHttpOrHttps(s) || isJalviewSchemeUri(s))
+    {
+      return true;
+    }
+    try
+    {
+      URI u = new URI(s);
+      // allow file:/home/... as well as file:///home... as java copes
+      if (s.startsWith("file:/"))
+      {
+        return true;
+      }
+    } catch (URISyntaxException e)
+    {
+      return false;
+    }
+    return false;
+  }
 
   /**
    * Returns true if it is possible to open an input stream at the given URL,
@@ -45,7 +71,7 @@ public class HttpUtils
     InputStream is = null;
     try
     {
-      is = new URL(url).openStream();
+      is = HttpUtils.openStream(new URL(url));
       if (is != null)
       {
         return true;
@@ -91,57 +117,202 @@ public class HttpUtils
     // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
 
     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
-    connection.setRequestMethod(HttpMethod.HEAD);
-
+    connection.setRequestMethod("HEAD");
     connection.setDoInput(true);
-
     connection.setUseCaches(false);
     connection.setConnectTimeout(300);
     connection.setReadTimeout(readTimeout);
-    return connection.getResponseCode() == 200;
+
+    // HttpURLConnection doesn't follow redirects from http to https. It should!
+    HttpURLConnection conn = followConnection(connection);
+    return conn.getResponseCode() == 200;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param HttpURLConnection
+   *          conn0
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection followConnection(HttpURLConnection conn0)
+          throws IOException
+  {
+    URL url = conn0.getURL();
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    int response = conn0.getResponseCode();
+    boolean followed = false;
+    if (response >= 300 && response < 400 && conn0.getFollowRedirects())
+    {
+      // we are only checking for a redirect from http to https
+      if ("http".equals(url.getProtocol()))
+      {
+        URL loc = new URL(conn0.getHeaderField("Location"));
+        if (loc != null && "https".equals(loc.getProtocol()))
+        {
+          conn = (HttpURLConnection) loc.openConnection();
+          conn.setRequestMethod(conn0.getRequestMethod());
+          conn.setDoInput(conn0.getDoInput());
+          conn.setUseCaches(conn0.getUseCaches());
+          conn.setConnectTimeout(conn0.getConnectTimeout());
+          conn.setReadTimeout(conn0.getReadTimeout());
+          conn.setInstanceFollowRedirects(
+                  conn0.getInstanceFollowRedirects());
+          followed = true;
+        }
+      }
+    }
+    return followed && conn != null ? conn : conn0;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static URLConnection openConnection(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    URLConnection conn = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
+      if (conn0 != null)
+      {
+        conn = HttpUtils.followConnection(conn0);
+      }
+      else
+      {
+        conn = conn0;
+      }
+    }
+    else
+    {
+      conn = url.openConnection();
+    }
+    return conn;
   }
 
-  public static String getUserAgent()
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * and return the followed InputStream
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static InputStream openStream(URL url) throws IOException
   {
-    return getUserAgent(null);
+    if (url == null)
+    {
+      return null;
+    }
+    InputStream is = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn = HttpUtils
+              .followConnection((HttpURLConnection) url.openConnection());
+      if (conn != null)
+      {
+        is = conn.getInputStream();
+      }
+    }
+    else
+    {
+      is = url.openStream();
+    }
+    return is;
   }
 
-  public static String getUserAgent(String className)
+  /**
+   * check if a jalview:// scheme URL is given
+   * 
+   * @param String
+   *          uri
+   * @return boolean
+   */
+  public static boolean isJalviewSchemeUri(String jalviewUriString)
   {
-    StringBuilder sb = new StringBuilder();
-    sb.append("Jalview");
-    sb.append('/');
-    sb.append(Cache.getDefault("VERSION", "Unknown"));
-    sb.append(" (");
-    sb.append(System.getProperty("os.name"));
-    sb.append("; ");
-    sb.append(System.getProperty("os.arch"));
-    sb.append(' ');
-    sb.append(System.getProperty("os.name"));
-    sb.append(' ');
-    sb.append(System.getProperty("os.version"));
-    sb.append("; ");
-    sb.append("java/");
-    sb.append(System.getProperty("java.version"));
-    sb.append("; ");
-    sb.append("jalview/");
-    sb.append(ChannelProperties.getProperty("channel"));
-    if (className != null)
-    {
-      sb.append("; ");
-      sb.append(className);
-    }
-    String installation = Cache.applicationProperties
-            .getProperty("INSTALLATION");
-    if (installation != null)
-    {
-      sb.append("; ");
-      sb.append(installation);
-    }
-    sb.append(')');
-    sb.append(" help@jalview.org");
-    return sb.toString();
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return false;
+    }
+    String scheme = jalviewUri.getScheme();
+    if (scheme == null || !scheme.startsWith(JALVIEWSCHEMEPREFIX))
+    {
+      return false;
+    }
+    int jspl = JALVIEWSCHEMEPREFIX.length();
+    return scheme.length() == jspl // jalview
+            || scheme.length() == jspl + 1 // jalviewX
+            || scheme.substring(jspl).equals("http") // jalviewhttp
+            || scheme.substring(jspl).equals("https"); // jalviewhttps
   }
 
+  /**
+   * convert a jalview scheme URI to its equivalent URL or path
+   * 
+   * @param String
+   *          uri
+   * @return String
+   */
+  public static String equivalentJalviewUrl(String jalviewUriString)
+  {
+    if (!isJalviewSchemeUri(jalviewUriString))
+    {
+      // not a jalviewUriString, hand it back
+      return jalviewUriString;
+    }
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return null;
+    }
+    String scheme = jalviewUri.getScheme();
+    String host = jalviewUri.getHost();
+    if (host != null && host.length() > 0 || scheme
+            .substring(JALVIEWSCHEMEPREFIX.length()).startsWith("http"))
+    {
+      URI newUri;
+      try
+      {
+        newUri = new URI(
+                scheme.equals(JALVIEWSCHEMEPREFIX + "http") ? "http"
+                        : "https",
+                jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
+                jalviewUri.getPath(), jalviewUri.getQuery(),
+                jalviewUri.getFragment());
+        // return a URL
+        return newUri.toURL().toString();
+      } catch (URISyntaxException | MalformedURLException e)
+      {
+        ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
+                + "' to URL failed");
+      }
+    }
+    else
+    {
+      // return a file path (not a file URI)
+      return jalviewUri.getPath();
+    }
+    return null;
+  }
 }