c607840ba5d3eed29ada95d72c64e89db4af09b3
[jalview.git] / getdown / src / getdown / core / src / main / java / jalview / util / HttpUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.HttpURLConnection;
26 import java.net.MalformedURLException;
27 import java.net.ProtocolException;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.net.URL;
31 import java.net.URLConnection;
32
33 public class HttpUtils
34 {
35   public final static String JALVIEWSCHEMEPREFIX = "jalview";
36
37   /**
38    * Returns true if it is possible to open an input stream at the given URL,
39    * else false. The input stream is closed.
40    * 
41    * @param url
42    * @return
43    */
44   public static boolean isValidUrl(String url)
45   {
46     InputStream is = null;
47     try
48     {
49       is = HttpUtils.openStream(new URL(url));
50       if (is != null)
51       {
52         return true;
53       }
54     } catch (IOException x)
55     {
56       // MalformedURLException, FileNotFoundException
57       return false;
58     } finally
59     {
60       if (is != null)
61       {
62         try
63         {
64           is.close();
65         } catch (IOException e)
66         {
67           // ignore
68         }
69       }
70     }
71     return false;
72   }
73
74   public static boolean startsWithHttpOrHttps(String file)
75   {
76     return file.startsWith("http://") || file.startsWith("https://");
77   }
78
79   public static boolean startsWithHttpOrHttpsOrJalviewScheme(String file)
80   {
81     if (startsWithHttpOrHttps(file))
82     {
83       return true;
84     }
85     return isJalviewSchemeUri(file);
86   }
87
88   /**
89    * wrapper to get/post to a URL or check headers
90    * 
91    * @param url
92    * @param ids
93    * @param readTimeout
94    * @return
95    * @throws IOException
96    * @throws ProtocolException
97    */
98   public static boolean checkUrlAvailable(URL url, int readTimeout)
99           throws IOException, ProtocolException
100   {
101     // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
102
103     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
104     connection.setRequestMethod("HEAD");
105     connection.setDoInput(true);
106     connection.setUseCaches(false);
107     connection.setConnectTimeout(300);
108     connection.setReadTimeout(readTimeout);
109
110     // HttpURLConnection doesn't follow redirects from http to https. It should!
111     HttpURLConnection conn = followConnection(connection);
112     return conn.getResponseCode() == 200;
113   }
114
115   /**
116    * wrapper to follow a URL connection ALLOWING redirects from http to https
117    * 
118    * @param HttpURLConnection
119    *          conn0
120    * @return HttpUrlConnection conn
121    */
122   public static HttpURLConnection followConnection(HttpURLConnection conn0)
123           throws IOException
124   {
125     URL url = conn0.getURL();
126     if (url == null)
127     {
128       return null;
129     }
130     HttpURLConnection conn = null;
131     int response = conn0.getResponseCode();
132     boolean followed = false;
133     if (response >= 300 && response < 400 && conn0.getFollowRedirects())
134     {
135       // we are only checking for a redirect from http to https
136       if ("http".equals(url.getProtocol()))
137       {
138         URL loc = new URL(conn0.getHeaderField("Location"));
139         if (loc != null && "https".equals(loc.getProtocol()))
140         {
141           conn = (HttpURLConnection) loc.openConnection();
142           conn.setRequestMethod(conn0.getRequestMethod());
143           conn.setDoInput(conn0.getDoInput());
144           conn.setUseCaches(conn0.getUseCaches());
145           conn.setConnectTimeout(conn0.getConnectTimeout());
146           conn.setReadTimeout(conn0.getReadTimeout());
147           conn.setInstanceFollowRedirects(
148                   conn0.getInstanceFollowRedirects());
149           followed = true;
150         }
151       }
152     }
153     return followed && conn != null ? conn : conn0;
154   }
155
156   /**
157    * wrapper to follow a URL connection ALLOWING redirects from http to https
158    * 
159    * @param URL
160    *          url
161    * @return HttpUrlConnection conn
162    */
163   public static URLConnection openConnection(URL url) throws IOException
164   {
165     if (url == null)
166     {
167       return null;
168     }
169     URLConnection conn = null;
170     String protocol = url.getProtocol();
171     if ("http".equals(protocol) || "https".equals(protocol))
172     {
173       HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
174       if (conn0 != null)
175       {
176         conn = HttpUtils.followConnection(conn0);
177       }
178       else
179       {
180         conn = conn0;
181       }
182     }
183     else
184     {
185       conn = url.openConnection();
186     }
187     return conn;
188   }
189
190   /**
191    * wrapper to follow a URL connection ALLOWING redirects from http to https
192    * and return the followed InputStream
193    * 
194    * @param URL
195    *          url
196    * @return HttpUrlConnection conn
197    */
198   public static InputStream openStream(URL url) throws IOException
199   {
200     if (url == null)
201     {
202       return null;
203     }
204     InputStream is = null;
205     String protocol = url.getProtocol();
206     if ("http".equals(protocol) || "https".equals(protocol))
207     {
208       HttpURLConnection conn = HttpUtils
209               .followConnection((HttpURLConnection) url.openConnection());
210       if (conn != null)
211       {
212         is = conn.getInputStream();
213       }
214     }
215     else
216     {
217       is = url.openStream();
218     }
219     return is;
220   }
221
222   /**
223    * check if a jalview:// scheme URL is given
224    * 
225    * @param String
226    *          uri
227    * @return boolean
228    */
229   public static boolean isJalviewSchemeUri(String jalviewUriString)
230   {
231     URI jalviewUri;
232     try
233     {
234       jalviewUri = new URI(jalviewUriString);
235     } catch (URISyntaxException e)
236     {
237       return false;
238     }
239     String scheme = jalviewUri.getScheme();
240     if (scheme == null || !scheme.startsWith(JALVIEWSCHEMEPREFIX))
241     {
242       return false;
243     }
244     int jspl = JALVIEWSCHEMEPREFIX.length();
245     return scheme.length() == jspl // jalview
246             || scheme.length() == jspl + 1 // jalviewX
247             || scheme.substring(jspl).equals("http") // jalviewhttp
248             || scheme.substring(jspl).equals("https"); // jalviewhttps
249   }
250
251   /**
252    * convert a jalview scheme URI to its equivalent URL or path
253    * 
254    * @param String
255    *          uri
256    * @return String
257    */
258   public static String equivalentJalviewUrl(String jalviewUriString)
259   {
260     if (!isJalviewSchemeUri(jalviewUriString))
261     {
262       // not a jalviewUriString, hand it back
263       return jalviewUriString;
264     }
265     URI jalviewUri;
266     try
267     {
268       jalviewUri = new URI(jalviewUriString);
269     } catch (URISyntaxException e)
270     {
271       return null;
272     }
273     String scheme = jalviewUri.getScheme();
274     String host = jalviewUri.getHost();
275     if (host != null && host.length() > 0 || scheme
276             .substring(JALVIEWSCHEMEPREFIX.length()).startsWith("http"))
277     {
278       URI newUri;
279       try
280       {
281         newUri = new URI(
282                 scheme.equals(JALVIEWSCHEMEPREFIX + "http") ? "http"
283                         : "https",
284                 jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
285                 jalviewUri.getPath(), jalviewUri.getQuery(),
286                 jalviewUri.getFragment());
287         // return a URL
288         return newUri.toURL().toString();
289       } catch (URISyntaxException | MalformedURLException e)
290       {
291         ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
292                 + "' to URL failed");
293       }
294     }
295     else
296     {
297       // return a file path (not a file URI)
298       return jalviewUri.getPath();
299     }
300     return null;
301   }
302 }