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