-/*******************************************************************************
+/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see <http://www.gnu.org/licenses/>.
* The Jalview Authors are detailed in the 'AUTHORS' file.
- ******************************************************************************/
+ */
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 java.net.URLConnection;
+
+import jalview.bin.Console;
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,
InputStream is = null;
try
{
- is = new URL(url).openStream();
+ is = HttpUtils.openStream(new URL(url));
if (is != null)
{
return true;
return false;
}
+ public static boolean startsWithHttpOrHttps(String file)
+ {
+ return file.startsWith("http://") || file.startsWith("https://");
+ }
+
+ /**
+ * wrapper to get/post to a URL or check headers
+ *
+ * @param url
+ * @param ids
+ * @param readTimeout
+ * @return
+ * @throws IOException
+ * @throws ProtocolException
+ */
+ public static boolean checkUrlAvailable(URL url, int readTimeout)
+ throws IOException, ProtocolException
+ {
+ // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
+
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("HEAD");
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+ connection.setConnectTimeout(300);
+ connection.setReadTimeout(readTimeout);
+
+ // HttpURLConnection doesn't follow redirects from http to https. It should!
+ HttpURLConnection conn = followConnection(connection);
+ return conn.getResponseCode() == 200;
+ }
+
+ /**
+ * wrapper to return a new HttpURLConnection to a new URL when there is a
+ * redirect from http to https, otherwise return the unused original
+ * HttpURLConnection
+ *
+ * @param HttpURLConnection
+ * conn0
+ * @return HttpUrlConnection conn
+ */
+ public static HttpURLConnection followConnection(HttpURLConnection conn0)
+ throws IOException
+ {
+ return followConnection(conn0, false);
+ }
+
+ public static HttpURLConnection followConnection(HttpURLConnection conn0,
+ boolean followAnyway) throws IOException
+ {
+ URL url = conn0.getURL();
+ // we are only checking for a redirect from http to https otherwise the java
+ // connection will follow when called (if not unset)
+ if (url == null)
+ {
+ return conn0;
+ }
+ if (!conn0.getInstanceFollowRedirects())
+ {
+ return conn0;
+ }
+ if (!"http".equals(url.getProtocol()) && !followAnyway)
+ {
+ return conn0;
+ }
+
+ // check the response code
+ HttpURLConnection checkConn = (HttpURLConnection) url.openConnection();
+ httpURLConnectionCopyAttributes(conn0, checkConn);
+
+ boolean redirectToHttps = false;
+ int response = checkConn.getResponseCode();
+ checkConn.disconnect();
+ if (response >= 300 && response < 400)
+ {
+ // we are only checking for a redirect from http to https
+ URL loc = new URL(conn0.getHeaderField("Location"));
+ if (loc != null && "https".equals(loc.getProtocol()))
+ {
+ redirectToHttps = true;
+ url = loc;
+ }
+ }
+ else if (followAnyway)
+ {
+ // checkConn might have followed a https->https redirect
+ url = checkConn.getURL();
+ }
+
+ if (!redirectToHttps && !followAnyway)
+ {
+ return conn0;
+ }
+
+ // We want to return an HttpURLConnection to the new (probably https) URL
+ // that is unconnected in case further manipulation of the request is
+ // required.
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ httpURLConnectionCopyAttributes(conn0, conn);
+ return conn;
+ }
+
+ private static void httpURLConnectionCopyAttributes(
+ HttpURLConnection conn0, HttpURLConnection conn1)
+ throws ProtocolException
+ {
+ conn1.setRequestMethod(conn0.getRequestMethod());
+ conn1.setDoInput(conn0.getDoInput());
+ conn1.setUseCaches(conn0.getUseCaches());
+ conn1.setConnectTimeout(conn0.getConnectTimeout());
+ conn1.setReadTimeout(conn0.getReadTimeout());
+ conn1.setInstanceFollowRedirects(conn0.getInstanceFollowRedirects());
+ }
+
+ /**
+ * 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
+ {
+ return openConnection(url, false);
+ }
+
+ public static URLConnection openConnection(URL url, boolean followAnyway)
+ throws IOException
+ {
+ if (url == null)
+ {
+ Console.debug("HttpUtils.openConnection(url) called with null url");
+ return null;
+ }
+ Console.debug("HttpUtils.openConnection(url) called with url="
+ + url.toString());
+ 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, followAnyway);
+ }
+ else
+ {
+ conn = conn0;
+ }
+ }
+ else
+ {
+ conn = url.openConnection();
+ }
+ return conn;
+ }
+
+ /**
+ * 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 openStream(url, false);
+ }
+
+ public static InputStream openStream(URL url, boolean followAnyway)
+ throws IOException
+ {
+ 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(), followAnyway);
+ if (conn != null)
+ {
+ is = conn.getInputStream();
+ }
+ }
+ else
+ {
+ is = url.openStream();
+ }
+ return is;
+ }
+
+ /**
+ * check if a jalview:// scheme URL is given
+ *
+ * @param String
+ * uri
+ * @return boolean
+ */
+ public static boolean isJalviewSchemeUri(String jalviewUriString)
+ {
+ if (jalviewUriString == null)
+ {
+ return false;
+ }
+ 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;
+ }
}