44880a0e4c01f6ecb849c20cb3d41ecb2e87d866
[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   public static boolean isPlausibleUri(String s)
38   {
39     if (s == null)
40     {
41       return false;
42     }
43     if (startsWithHttpOrHttps(s) || isJalviewSchemeUri(s))
44     {
45       return true;
46     }
47     try
48     {
49       URI u = new URI(s);
50       // allow file:/home/... as well as file:///home... as java copes
51       if (s.startsWith("file:/"))
52       {
53         return true;
54       }
55     } catch (URISyntaxException e)
56     {
57       return false;
58     }
59     return false;
60   }
61
62   /**
63    * Returns true if it is possible to open an input stream at the given URL,
64    * else false. The input stream is closed.
65    * 
66    * @param url
67    * @return
68    */
69   public static boolean isValidUrl(String url)
70   {
71     InputStream is = null;
72     try
73     {
74       is = HttpUtils.openStream(new URL(url));
75       if (is != null)
76       {
77         return true;
78       }
79     } catch (IOException x)
80     {
81       // MalformedURLException, FileNotFoundException
82       return false;
83     } finally
84     {
85       if (is != null)
86       {
87         try
88         {
89           is.close();
90         } catch (IOException e)
91         {
92           // ignore
93         }
94       }
95     }
96     return false;
97   }
98
99   public static boolean startsWithHttpOrHttps(String file)
100   {
101     return file.startsWith("http://") || file.startsWith("https://");
102   }
103
104   /**
105    * wrapper to get/post to a URL or check headers
106    * 
107    * @param url
108    * @param ids
109    * @param readTimeout
110    * @return
111    * @throws IOException
112    * @throws ProtocolException
113    */
114   public static boolean checkUrlAvailable(URL url, int readTimeout)
115           throws IOException, ProtocolException
116   {
117     // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
118
119     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
120     connection.setRequestMethod("HEAD");
121     connection.setDoInput(true);
122     connection.setUseCaches(false);
123     connection.setConnectTimeout(300);
124     connection.setReadTimeout(readTimeout);
125
126     // HttpURLConnection doesn't follow redirects from http to https. It should!
127     HttpURLConnection conn = followConnection(connection);
128     return conn.getResponseCode() == 200;
129   }
130
131   /**
132    * wrapper to follow a URL connection ALLOWING redirects from http to https
133    * 
134    * @param HttpURLConnection
135    *          conn0
136    * @return HttpUrlConnection conn
137    */
138   public static HttpURLConnection followConnection(HttpURLConnection conn0)
139           throws IOException
140   {
141     URL url = conn0.getURL();
142     if (url == null)
143     {
144       return null;
145     }
146     HttpURLConnection conn = null;
147     int response = conn0.getResponseCode();
148     boolean followed = false;
149     if (response >= 300 && response < 400 && conn0.getFollowRedirects())
150     {
151       // we are only checking for a redirect from http to https
152       if ("http".equals(url.getProtocol()))
153       {
154         URL loc = new URL(conn0.getHeaderField("Location"));
155         if (loc != null && "https".equals(loc.getProtocol()))
156         {
157           conn = (HttpURLConnection) loc.openConnection();
158           conn.setRequestMethod(conn0.getRequestMethod());
159           conn.setDoInput(conn0.getDoInput());
160           conn.setUseCaches(conn0.getUseCaches());
161           conn.setConnectTimeout(conn0.getConnectTimeout());
162           conn.setReadTimeout(conn0.getReadTimeout());
163           conn.setInstanceFollowRedirects(
164                   conn0.getInstanceFollowRedirects());
165           followed = true;
166         }
167       }
168     }
169     return followed && conn != null ? conn : conn0;
170   }
171
172   /**
173    * wrapper to follow a URL connection ALLOWING redirects from http to https
174    * 
175    * @param URL
176    *          url
177    * @return HttpUrlConnection conn
178    */
179   public static URLConnection openConnection(URL url) throws IOException
180   {
181     if (url == null)
182     {
183       return null;
184     }
185     URLConnection conn = null;
186     String protocol = url.getProtocol();
187     if ("http".equals(protocol) || "https".equals(protocol))
188     {
189       HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
190       if (conn0 != null)
191       {
192         conn = HttpUtils.followConnection(conn0);
193       }
194       else
195       {
196         conn = conn0;
197       }
198     }
199     else
200     {
201       conn = url.openConnection();
202     }
203     return conn;
204   }
205
206   /**
207    * wrapper to follow a URL connection ALLOWING redirects from http to https
208    * and return the followed InputStream
209    * 
210    * @param URL
211    *          url
212    * @return HttpUrlConnection conn
213    */
214   public static InputStream openStream(URL url) throws IOException
215   {
216     if (url == null)
217     {
218       return null;
219     }
220     InputStream is = null;
221     String protocol = url.getProtocol();
222     if ("http".equals(protocol) || "https".equals(protocol))
223     {
224       HttpURLConnection conn = HttpUtils
225               .followConnection((HttpURLConnection) url.openConnection());
226       if (conn != null)
227       {
228         is = conn.getInputStream();
229       }
230     }
231     else
232     {
233       is = url.openStream();
234     }
235     return is;
236   }
237
238   /**
239    * check if a jalview:// scheme URL is given
240    * 
241    * @param String
242    *          uri
243    * @return boolean
244    */
245   public static boolean isJalviewSchemeUri(String jalviewUriString)
246   {
247     URI jalviewUri;
248     try
249     {
250       jalviewUri = new URI(jalviewUriString);
251     } catch (URISyntaxException e)
252     {
253       return false;
254     }
255     String scheme = jalviewUri.getScheme();
256     if (scheme == null || !scheme.startsWith(JALVIEWSCHEMEPREFIX))
257     {
258       return false;
259     }
260     int jspl = JALVIEWSCHEMEPREFIX.length();
261     return scheme.length() == jspl // jalview
262             || scheme.length() == jspl + 1 // jalviewX
263             || scheme.substring(jspl).equals("http") // jalviewhttp
264             || scheme.substring(jspl).equals("https"); // jalviewhttps
265   }
266
267   /**
268    * convert a jalview scheme URI to its equivalent URL or path
269    * 
270    * @param String
271    *          uri
272    * @return String
273    */
274   public static String equivalentJalviewUrl(String jalviewUriString)
275   {
276     if (!isJalviewSchemeUri(jalviewUriString))
277     {
278       // not a jalviewUriString, hand it back
279       return jalviewUriString;
280     }
281     URI jalviewUri;
282     try
283     {
284       jalviewUri = new URI(jalviewUriString);
285     } catch (URISyntaxException e)
286     {
287       return null;
288     }
289     String scheme = jalviewUri.getScheme();
290     String host = jalviewUri.getHost();
291     if (host != null && host.length() > 0 || scheme
292             .substring(JALVIEWSCHEMEPREFIX.length()).startsWith("http"))
293     {
294       URI newUri;
295       try
296       {
297         newUri = new URI(
298                 scheme.equals(JALVIEWSCHEMEPREFIX + "http") ? "http"
299                         : "https",
300                 jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
301                 jalviewUri.getPath(), jalviewUri.getQuery(),
302                 jalviewUri.getFragment());
303         // return a URL
304         return newUri.toURL().toString();
305       } catch (URISyntaxException | MalformedURLException e)
306       {
307         ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
308                 + "' to URL failed");
309       }
310     }
311     else
312     {
313       // return a file path (not a file URI)
314       return jalviewUri.getPath();
315     }
316     return null;
317   }
318 }