001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.network; 020 021import java.awt.Desktop; 022import java.awt.Desktop.Action; 023import java.io.BufferedInputStream; 024import java.io.BufferedReader; 025import java.io.ByteArrayOutputStream; 026import java.io.DataOutputStream; 027import java.io.EOFException; 028import java.io.File; 029import java.io.FileInputStream; 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.InputStreamReader; 033import java.io.UnsupportedEncodingException; 034import java.lang.reflect.Method; 035import java.net.Authenticator; 036import java.net.HttpURLConnection; 037import java.net.InetSocketAddress; 038import java.net.PasswordAuthentication; 039import java.net.Socket; 040import java.net.URI; 041import java.net.URISyntaxException; 042import java.net.URL; 043import java.net.URLConnection; 044import java.net.URLDecoder; 045import java.net.URLEncoder; 046import java.security.cert.CertificateException; 047import java.security.cert.X509Certificate; 048import java.util.HashMap; 049import java.util.HashSet; 050import java.util.Map; 051import java.util.Map.Entry; 052import java.util.Set; 053 054import javax.net.ssl.HostnameVerifier; 055import javax.net.ssl.HttpsURLConnection; 056import javax.net.ssl.SSLContext; 057import javax.net.ssl.SSLEngine; 058import javax.net.ssl.SSLSession; 059import javax.net.ssl.TrustManager; 060 061import icy.common.Version; 062import icy.common.listener.ProgressListener; 063import icy.common.listener.weak.WeakListener; 064import icy.file.FileUtil; 065import icy.preferences.NetworkPreferences; 066import icy.system.IcyExceptionHandler; 067import icy.system.SystemUtil; 068import icy.system.audit.Audit; 069import icy.system.thread.ThreadUtil; 070import icy.util.StringUtil; 071 072/** 073 * @author stephane 074 */ 075public class NetworkUtil 076{ 077 /** 078 * URL 079 */ 080 public static final String WEBSITE_HOST = "icy.bioimageanalysis.org"; 081 public static final String WEBSITE_URL = "http://" + WEBSITE_HOST + "/"; 082 083 static final String REPORT_URL = WEBSITE_URL + "index.php"; 084 085 /** 086 * Parameters id 087 */ 088 public static final String ID_KERNELVERSION = "kernelVersion"; 089 public static final String ID_BETAALLOWED = "betaAllowed"; 090 public static final String ID_JAVANAME = "javaName"; 091 public static final String ID_JAVAVERSION = "javaVersion"; 092 public static final String ID_JAVABITS = "javaBits"; 093 public static final String ID_OSNAME = "osName"; 094 public static final String ID_OSVERSION = "osVersion"; 095 public static final String ID_OSARCH = "osArch"; 096 public static final String ID_PLUGINCLASSNAME = "pluginClassName"; 097 public static final String ID_PLUGINVERSION = "pluginVersion"; 098 public static final String ID_DEVELOPERID = "developerId"; 099 public static final String ID_ERRORLOG = "errorLog"; 100 101 /** 102 * Proxy config ID 103 */ 104 public static final int NO_PROXY = 0; 105 public static final int SYSTEM_PROXY = 1; 106 public static final int USER_PROXY = 2; 107 108 public interface InternetAccessListener 109 { 110 /** 111 * Internet connection available. 112 */ 113 public void internetUp(); 114 115 /** 116 * Internet connection no more available. 117 */ 118 public void internetDown(); 119 } 120 121 /** 122 * Weak listener wrapper for NetworkConnectionListener. 123 * 124 * @author Stephane 125 */ 126 public static class WeakInternetAccessListener extends WeakListener<InternetAccessListener> 127 implements InternetAccessListener 128 { 129 public WeakInternetAccessListener(InternetAccessListener listener) 130 { 131 super(listener); 132 } 133 134 @Override 135 public void removeListener(Object source) 136 { 137 removeInternetAccessListener(this); 138 } 139 140 @Override 141 public void internetUp() 142 { 143 final InternetAccessListener listener = getListener(); 144 145 if (listener != null) 146 listener.internetUp(); 147 } 148 149 @Override 150 public void internetDown() 151 { 152 final InternetAccessListener listener = getListener(); 153 154 if (listener != null) 155 listener.internetDown(); 156 } 157 } 158 159 /** 160 * Internet monitor thread 161 */ 162 private static class InternetMonitorThread extends Thread 163 { 164 public InternetMonitorThread() 165 { 166 super("Internet monitor"); 167 } 168 169 @Override 170 public void run() 171 { 172 while (!isInterrupted()) 173 { 174 try 175 { 176 final Socket socket = new Socket(); 177 178 // timeout = 3 seconds 179 socket.setSoTimeout(3000); 180 socket.connect(new InetSocketAddress(WEBSITE_HOST, 80), 3000); 181 socket.close(); 182 183 // we have internet access 184 setInternetAccess(true); 185 } 186 catch (Throwable t1) 187 { 188 // in case we use proxy 189 try 190 { 191 final URLConnection urlConnection = openConnection("http://www.google.com", true, false); 192 193 if (urlConnection != null) 194 { 195 urlConnection.setConnectTimeout(3000); 196 urlConnection.setReadTimeout(3000); 197 urlConnection.getInputStream(); 198 199 // we have internet access 200 setInternetAccess(true); 201 } 202 else 203 // we don't have internet access 204 setInternetAccess(false); 205 } 206 catch (Throwable t2) 207 { 208 // we don't have internet access 209 setInternetAccess(false); 210 } 211 } 212 213 // wait a bit depending connection state 214 ThreadUtil.sleep(hasInternetAccess() ? 30000 : 5000); 215 } 216 } 217 }; 218 219 /** 220 * 'Accept all' host name verifier 221 */ 222 private static class FakeHostnameVerifier implements HostnameVerifier 223 { 224 public FakeHostnameVerifier() 225 { 226 super(); 227 } 228 229 @Override 230 public boolean verify(String hostname, SSLSession session) 231 { 232 // always return true 233 return true; 234 } 235 }; 236 237 /** 238 * List of all listeners on network connection changes. 239 */ 240 private final static Set<InternetAccessListener> listeners = new HashSet<InternetAccessListener>();; 241 242 /** 243 * Internet monitor 244 */ 245 public static final InternetMonitorThread internetMonitor = new InternetMonitorThread(); 246 /** 247 * Internet access up flag 248 */ 249 private static boolean internetAccess; 250 /** 251 * internal HTTPS compatibility for the new web site 252 */ 253 private static boolean httpsSupported; 254 255 public static void init() 256 { 257 internetAccess = false; 258 httpsSupported = false; 259 260 // check for HTTPS "let's encrypt" certificate compatibility 261 final Version javaVersion = SystemUtil.getJavaVersionAsVersion(); 262 final int javaInt = javaVersion.getMajor(); 263 264 if (javaInt == 7) 265 httpsSupported = javaVersion.isGreaterOrEqual(new Version("7.0.111")); 266 else if (javaInt == 8) 267 httpsSupported = javaVersion.isGreaterOrEqual(new Version("8.0.101")); 268 else 269 httpsSupported = (javaInt >= 9); 270 271 updateNetworkSetting(); 272 // accept all HTTPS connections by default 273 installTruster(); 274 275 // String addr; 276 // 277 // // --> connection HTTPS: fails with java 7, ok with java 8 (let's encrypt certificate) 278 // addr = "https://icy.yhello.co"; 279 // // addr = "http://icy.yhello.co/update/update.php?arch=win64&version=1.9.8.2"; 280 // // addr = "https://icy.yhello.co/update/update.php?arch=win64&version=1.9.8.2"; 281 // // addr = "https://icy.yhello.co/register/getLinkedUserInfo.php?IcyId=4817172"; 282 // // addr = "https://randomuser.me/"; 283 // 284 // try 285 // { 286 // HttpURLConnection uc = (HttpURLConnection) new URL(addr).openConnection(); 287 // uc.connect(); 288 // if (uc instanceof HttpsURLConnection) 289 // System.out.println(((HttpsURLConnection) uc).getLocalPrincipal()); 290 // if (uc instanceof HttpURLConnection) 291 // System.out.println(((HttpURLConnection) uc).getResponseCode() + " - " 292 // + ((HttpURLConnection) uc).getResponseMessage()); 293 // 294 // InputStream inputStream = uc.getInputStream(); 295 // inputStream.read(); 296 // uc.disconnect(); 297 // } 298 // catch (Exception e) 299 // { 300 // // TODO Auto-generated catch block 301 // e.printStackTrace(); 302 // } 303 304 // start monitor thread 305 internetMonitor.setPriority(Thread.MIN_PRIORITY); 306 internetMonitor.start(); 307 } 308 309 private static void installTruster() 310 { 311 // enable support for TLS v1.X (used by new Icy web site: TLS 1.2 or TLS 1.3) 312 System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2"); 313 314 try 315 { 316 // install the accept all host name verifier 317 HttpsURLConnection.setDefaultHostnameVerifier(new FakeHostnameVerifier()); 318 319 // create a trust manager that does not validate certificate chains (Accept all certificates) 320 final TrustManager[] trustAllCerts = new TrustManager[] {new javax.net.ssl.X509ExtendedTrustManager() 321 { 322 @Override 323 public java.security.cert.X509Certificate[] getAcceptedIssuers() 324 { 325 return null; 326 } 327 328 @Override 329 public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) 330 { 331 // ignore 332 // System.out.println(certs.length); 333 } 334 335 @Override 336 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) 337 { 338 // ignore 339 // System.out.println(certs.length + " - " + authType); 340 } 341 342 @Override 343 public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) 344 throws CertificateException 345 { 346 // ignore 347 // System.out.println(chain.length + " - " + authType); 348 } 349 350 @Override 351 public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) 352 throws CertificateException 353 { 354 // ignore 355 // System.out.println(chain.length + " - " + authType); 356 } 357 358 @Override 359 public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) 360 throws CertificateException 361 { 362 // ignore 363 // System.out.println(chain.length + " - " + authType); 364 } 365 366 @Override 367 public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) 368 throws CertificateException 369 { 370 // ignore 371 // System.out.println(chain.length + " - " + authType); 372 } 373 }}; 374 375 // install the all-trusting trust manager 376 SSLContext sc; 377 378 sc = SSLContext.getInstance("SSL"); 379 if (sc != null) 380 sc.init(null, trustAllCerts, new java.security.SecureRandom()); 381 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 382 383 sc = SSLContext.getInstance("TLS"); 384 if (sc != null) 385 sc.init(null, trustAllCerts, new java.security.SecureRandom()); 386 } 387 catch (Exception e) 388 { 389 IcyExceptionHandler.showErrorMessage(e, false, true); 390 } 391 } 392 393 /** 394 * Update network setting from the actual preferences 395 */ 396 public static void updateNetworkSetting() 397 { 398 HttpURLConnection.setFollowRedirects(false); 399 400 final int proxySetting = NetworkPreferences.getProxySetting(); 401 402 if (proxySetting == NO_PROXY) 403 { 404 // no proxy 405 disableProxySetting(); 406 disableHTTPProxySetting(); 407 disableHTTPSProxySetting(); 408 disableFTPProxySetting(); 409 disableSOCKSProxySetting(); 410 disableSystemProxy(); 411 } 412 else if (proxySetting == SYSTEM_PROXY) 413 { 414 // system proxy 415 disableProxySetting(); 416 disableHTTPProxySetting(); 417 disableHTTPSProxySetting(); 418 disableFTPProxySetting(); 419 disableSOCKSProxySetting(); 420 enableSystemProxy(); 421 } 422 else 423 { 424 final String user = NetworkPreferences.getProxyUser(); 425 final String pass = NetworkPreferences.getProxyPassword(); 426 final boolean auth = NetworkPreferences.getProxyAuthentication() && (!StringUtil.isEmpty(user)) 427 && (!StringUtil.isEmpty(pass)); 428 String host; 429 430 // authentication enabled ? 431 if (auth) 432 { 433 Authenticator.setDefault(new Authenticator() 434 { 435 @Override 436 public PasswordAuthentication getPasswordAuthentication() 437 { 438 return new PasswordAuthentication(user, pass.toCharArray()); 439 } 440 }); 441 } 442 443 // manual proxy 444 disableSystemProxy(); 445 446 // HTTP proxy (use it as general proxy) 447 host = NetworkPreferences.getProxyHTTPHost(); 448 if (!StringUtil.isEmpty(host)) 449 { 450 final int port = NetworkPreferences.getProxyHTTPPort(); 451 452 setProxyHost(host); 453 setProxyPort(port); 454 setHTTPProxyHost(host); 455 setHTTPProxyPort(port); 456 if (auth) 457 { 458 setHTTPProxyUser(user); 459 setHTTPProxyPassword(pass); 460 } 461 enableProxySetting(); 462 enableHTTPProxySetting(); 463 } 464 else 465 { 466 disableProxySetting(); 467 disableHTTPProxySetting(); 468 } 469 470 // HTTPS proxy 471 host = NetworkPreferences.getProxyHTTPSHost(); 472 if (!StringUtil.isEmpty(host)) 473 { 474 setHTTPSProxyHost(host); 475 setHTTPSProxyPort(NetworkPreferences.getProxyHTTPSPort()); 476 if (auth) 477 { 478 setHTTPSProxyUser(user); 479 setHTTPSProxyPassword(pass); 480 } 481 enableHTTPSProxySetting(); 482 } 483 else 484 disableHTTPSProxySetting(); 485 486 // FTP proxy 487 host = NetworkPreferences.getProxyFTPHost(); 488 if (!StringUtil.isEmpty(host)) 489 { 490 setFTPProxyHost(host); 491 setFTPProxyPort(NetworkPreferences.getProxyFTPPort()); 492 if (auth) 493 { 494 setFTPProxyUser(user); 495 setFTPProxyPassword(pass); 496 } 497 enableFTPProxySetting(); 498 } 499 else 500 disableFTPProxySetting(); 501 502 // SOCKS proxy 503 host = NetworkPreferences.getProxySOCKSHost(); 504 if (!StringUtil.isEmpty(host)) 505 { 506 setSOCKSProxyHost(host); 507 setSOCKSProxyPort(NetworkPreferences.getProxySOCKSPort()); 508 if (auth) 509 { 510 setSOCKSProxyUser(user); 511 setSOCKSProxyPassword(pass); 512 } 513 enableSOCKSProxySetting(); 514 } 515 else 516 disableSOCKSProxySetting(); 517 } 518 } 519 520 static void setInternetAccess(boolean value) 521 { 522 if (internetAccess != value) 523 { 524 internetAccess = value; 525 526 fireInternetConnectionEvent(value); 527 528 // local stuff to do on connection recovery 529 if (value) 530 { 531 // process id audit 532 Audit.onConnect(); 533 } 534 } 535 } 536 537 private static void fireInternetConnectionEvent(boolean value) 538 { 539 if (value) 540 { 541 for (InternetAccessListener l : listeners) 542 l.internetUp(); 543 } 544 else 545 { 546 for (InternetAccessListener l : listeners) 547 l.internetDown(); 548 } 549 } 550 551 /** 552 * Adds a new listener on internet access change. 553 */ 554 public static void addInternetAccessListener(InternetAccessListener listener) 555 { 556 listeners.add(listener); 557 } 558 559 /** 560 * Removes a listener on internet access change. 561 */ 562 public static void removeInternetAccessListener(InternetAccessListener listener) 563 { 564 listeners.remove(listener); 565 } 566 567 /** 568 * Returns true if we currently have Internet connection. 569 */ 570 public static boolean hasInternetAccess() 571 { 572 return internetAccess; 573 } 574 575 /** 576 * @deprecated Use {@link #hasInternetAccess()} instead. 577 */ 578 @Deprecated 579 public static boolean hasInternetConnection() 580 { 581 return hasInternetAccess(); 582 } 583 584 /** 585 * Returns true if HTTPS is supported for the new web site. 586 */ 587 public static boolean isHTTPSSupported() 588 { 589 return httpsSupported; 590 } 591 592 /** 593 * Open an URL in the default system browser 594 */ 595 public static boolean openBrowser(String url) 596 { 597 return openBrowser(URLUtil.getURL(url)); 598 } 599 600 /** 601 * Open an URL in the default system browser 602 */ 603 public static boolean openBrowser(URL url) 604 { 605 if (url == null) 606 return false; 607 608 try 609 { 610 return openBrowser(url.toURI()); 611 } 612 catch (URISyntaxException e) 613 { 614 // use other method 615 return systemOpenBrowser(url.toString()); 616 } 617 } 618 619 /** 620 * Open an URL in the default system browser 621 */ 622 public static boolean openBrowser(URI uri) 623 { 624 if (uri == null) 625 return false; 626 627 final Desktop desktop = SystemUtil.getDesktop(); 628 629 if ((desktop != null) && desktop.isSupported(Action.BROWSE)) 630 { 631 try 632 { 633 desktop.browse(uri); 634 return true; 635 } 636 catch (IOException e) 637 { 638 // ignore 639 } 640 } 641 642 // not 643 return systemOpenBrowser(uri.toString()); 644 } 645 646 /** 647 * Open an URL in the default system browser (low level method) 648 */ 649 private static boolean systemOpenBrowser(String url) 650 { 651 if (StringUtil.isEmpty(url)) 652 return false; 653 654 try 655 { 656 if (SystemUtil.isMac()) 657 { 658 Class<?> fileMgr = Class.forName("com.apple.eio.FileManager"); 659 Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] {String.class}); 660 openURL.invoke(null, new Object[] {url}); 661 } 662 else if (SystemUtil.isWindows()) 663 Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); 664 else 665 { 666 // assume Unix or Linux 667 String[] browsers = {"firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape"}; 668 String browser = null; 669 for (int count = 0; count < browsers.length && browser == null; count++) 670 { 671 if (Runtime.getRuntime().exec("which " + browsers[count]).waitFor() == 0) 672 browser = browsers[count]; 673 } 674 if (browser == null) 675 throw new Exception("Could not find web browser"); 676 677 Runtime.getRuntime().exec(new String[] {browser, url}); 678 } 679 680 return true; 681 } 682 catch (Exception e) 683 { 684 System.err.println("Error while opening system browser :\n" + e.toString()); 685 return false; 686 } 687 } 688 689 /** 690 * @deprecated Use {@link #openBrowser(String)} instead. 691 */ 692 @Deprecated 693 public static void openURL(String url) 694 { 695 openBrowser(url); 696 } 697 698 /** 699 * @deprecated Use {@link #openBrowser(URL)} instead. 700 */ 701 @Deprecated 702 public static void openURL(URL url) 703 { 704 openBrowser(url); 705 } 706 707 /** 708 * @deprecated Use {@link #openBrowser(URI)} instead. 709 */ 710 @Deprecated 711 public static void openURL(URI uri) 712 { 713 openBrowser(uri); 714 } 715 716 /** 717 * Download data from specified URL string and return it as an array of byte 718 */ 719 public static byte[] download(String path, ProgressListener listener, boolean displayError) 720 { 721 return download(path, null, null, listener, displayError); 722 } 723 724 /** 725 * Download data from specified URL string and return it as an array of byte 726 * Process authentication process if login / pass are not null. 727 */ 728 public static byte[] download(String path, String login, String pass, ProgressListener listener, 729 boolean displayError) 730 { 731 final File file = new File(FileUtil.getGenericPath(path)); 732 733 // path define a file ? 734 if (file.exists()) 735 return download(file, listener, displayError); 736 737 final URL url = URLUtil.getURL(path); 738 739 // error while building URL ? 740 if (url == null) 741 { 742 if (displayError) 743 System.out.println("Can't download '" + path + "', incorrect path !"); 744 745 return null; 746 } 747 748 return download(url, login, pass, listener, displayError); 749 } 750 751 /** 752 * Download data from specified URL and return it as an array of byte 753 */ 754 public static byte[] download(URL url, ProgressListener listener, boolean displayError) 755 { 756 return download(url, null, null, listener, displayError); 757 } 758 759 /** 760 * Download data from specified URL and return it as an array of byte.<br> 761 * Process authentication process if login / pass fields are not null.<br> 762 * It returns <code>null</code> if an error occurred. 763 */ 764 public static byte[] download(URL url, String login, String pass, ProgressListener listener, boolean displayError) 765 { 766 // check if this is a file 767 if ((url != null) && URLUtil.isFileURL(url)) 768 { 769 try 770 { 771 return download(new File(url.toURI()), listener, displayError); 772 } 773 catch (URISyntaxException e) 774 { 775 if (displayError) 776 System.out.println("Can't download from '" + url + "', incorrect path !"); 777 778 return null; 779 } 780 } 781 782 // get connection object and connect it 783 final URLConnection uc = openConnection(url, login, pass, true, true, displayError); 784 final InputStream ip = getInputStream(uc, displayError); 785 786 // error --> exit 787 if (ip == null) 788 return null; 789 790 try 791 { 792 return download(ip, uc.getContentLength(), listener); 793 } 794 catch (Exception e) 795 { 796 if (displayError) 797 { 798 System.out.println("Error while downloading '" + uc.getURL() + "' :"); 799 IcyExceptionHandler.showErrorMessage(e, false, false); 800 } 801 802 return null; 803 } 804 finally 805 { 806 try 807 { 808 ip.close(); 809 } 810 catch (IOException e) 811 { 812 // ignore... 813 } 814 } 815 } 816 817 /** 818 * Download data from File and return it as an array of byte.<br> 819 * It returns <code>null</code> if an error occurred (file not found or not existing, IO 820 * error...) 821 */ 822 public static byte[] download(File f, ProgressListener listener, boolean displayError) 823 { 824 if (!f.exists()) 825 { 826 System.err.println("File not found: " + f.getPath()); 827 return null; 828 } 829 830 try 831 { 832 return download(new FileInputStream(f), f.length(), listener); 833 } 834 catch (Exception e) 835 { 836 if (displayError) 837 { 838 System.out.println("NetworkUtil.download('" + f.getPath() + "',...) error :"); 839 IcyExceptionHandler.showErrorMessage(e, false, false); 840 } 841 842 return null; 843 } 844 } 845 846 /** 847 * Download data from specified InputStream and return it as an array of byte.<br> 848 * Returns <code>null</code> if load operation was interrupted by user. 849 */ 850 public static byte[] download(InputStream in, long len, ProgressListener listener) throws IOException 851 { 852 final int READ_BLOCKSIZE = 64 * 1024; 853 final BufferedInputStream bin; 854 855 if (in instanceof BufferedInputStream) 856 bin = (BufferedInputStream) in; 857 else 858 bin = new BufferedInputStream(in); 859 860 final ByteArrayOutputStream bout = new ByteArrayOutputStream((int) ((len > 0) ? len : READ_BLOCKSIZE)); 861 // read per block of 64 KB 862 final byte[] data = new byte[READ_BLOCKSIZE]; 863 864 try 865 { 866 int off = 0; 867 int count = 0; 868 869 while (count >= 0) 870 { 871 count = bin.read(data); 872 if (count <= 0) 873 { 874 // unexpected length 875 if ((len != -1) && (off != len)) 876 throw new EOFException("Unexpected end of file at " + off + " (" + len + " expected)"); 877 } 878 else 879 off += count; 880 881 // copy to dynamic buffer 882 if (count > 0) 883 bout.write(data, 0, count); 884 885 if (listener != null) 886 { 887 // download canceled ? 888 if (!listener.notifyProgress(off, len)) 889 { 890 in.close(); 891 System.out.println("Interrupted by user."); 892 return null; 893 } 894 } 895 } 896 } 897 finally 898 { 899 bin.close(); 900 } 901 902 return bout.toByteArray(); 903 } 904 905 /** 906 * Download data from specified InputStream and return it as an array of byte.<br> 907 * It returns <code>null</code> if an error occurred. 908 */ 909 public static byte[] download(InputStream in) throws IOException 910 { 911 return download(in, -1, null); 912 } 913 914 /** 915 * Returns a new {@link URLConnection} from specified URL (null if an error occurred). 916 * 917 * @param url 918 * url to connect. 919 * @param login 920 * login if the connection requires authentication.<br> 921 * Set it to null if no authentication needed. 922 * @param pass 923 * login if the connection requires authentication. 924 * Set it to null if no authentication needed. 925 * @param disableCache 926 * Disable proxy cache if any. 927 * @param doConnect 928 * do the connection before return the {@link URLConnection} object 929 * @param displayError 930 * Display error message in console if something wrong happen. 931 */ 932 public static URLConnection openConnection(URL url, String login, String pass, boolean disableCache, 933 boolean doConnect, boolean displayError) 934 { 935 if (url == null) 936 { 937 if (displayError) 938 System.out.println("NetworkUtil.openConnection(...) error: URL is null !"); 939 940 return null; 941 } 942 943 URLConnection uc = null; 944 945 try 946 { 947 uc = url.openConnection(); 948 boolean redirect; 949 950 do 951 { 952 redirect = false; 953 954 if (disableCache) 955 disableCache(uc); 956 957 // authentication 958 if (!StringUtil.isEmpty(login) && !StringUtil.isEmpty(pass)) 959 setAuthentication(uc, login, pass); 960 961 if (doConnect) 962 { 963 // try to connect 964 if (!connect(uc, displayError)) 965 // error ? --> return null 966 return null; 967 968 // we test response code for HTTP connection 969 if (uc instanceof HttpURLConnection) 970 { 971 final int respCode = ((HttpURLConnection) uc).getResponseCode(); 972 973 redirect = (respCode == HttpURLConnection.HTTP_MOVED_PERM) 974 || (respCode == HttpURLConnection.HTTP_MOVED_TEMP) 975 || (respCode == HttpURLConnection.HTTP_SEE_OTHER); 976 977 // redirection ? 978 if (redirect) 979 { 980 // restart connection with new URL 981 String location = ((HttpURLConnection) uc).getHeaderField("Location"); 982 ((HttpURLConnection) uc).disconnect(); 983 location = URLDecoder.decode(location, "UTF-8"); 984 uc = new URL(location).openConnection(); 985 } 986 } 987 } 988 } 989 while (redirect); 990 991 return uc; 992 } 993 catch (IOException e) 994 { 995 if (displayError) 996 { 997 // HTTPS not supported while we have a HTTPS connection to icy web site 998 if (!isHTTPSSupported() && (uc != null) 999 && uc.getURL().toString().toLowerCase().startsWith("https://icy")) 1000 { 1001 System.err.println("NetworkUtil.openConnection('" + uc.getURL() 1002 + "') error: HTTPS connection not supported (see detail below)."); 1003 IcyExceptionHandler.showErrorMessage(e, false, false); 1004 } 1005 else 1006 { 1007 System.out.println("NetworkUtil.openConnection('" + url + "') error :"); 1008 IcyExceptionHandler.showErrorMessage(e, false, false); 1009 } 1010 } 1011 1012 return null; 1013 } 1014 } 1015 1016 /** 1017 * Returns a new {@link URLConnection} from specified URL (null if an error occurred). 1018 * 1019 * @param url 1020 * url to connect. 1021 * @param login 1022 * login if the connection requires authentication.<br> 1023 * Set it to null if no authentication needed. 1024 * @param pass 1025 * login if the connection requires authentication. 1026 * Set it to null if no authentication needed. 1027 * @param disableCache 1028 * Disable proxy cache if any. 1029 * @param displayError 1030 * Display error message in console if something wrong happen. 1031 */ 1032 public static URLConnection openConnection(URL url, String login, String pass, boolean disableCache, 1033 boolean displayError) 1034 { 1035 return openConnection(url, login, pass, disableCache, false, displayError); 1036 } 1037 1038 /** 1039 * Returns a new {@link URLConnection} from specified URL (null if an error occurred). 1040 * 1041 * @param url 1042 * url to connect. 1043 * @param auth 1044 * Authentication informations. 1045 * @param disableCache 1046 * Disable proxy cache if any. 1047 * @param displayError 1048 * Display error message in console if something wrong happen. 1049 */ 1050 public static URLConnection openConnection(URL url, AuthenticationInfo auth, boolean disableCache, 1051 boolean displayError) 1052 { 1053 if ((auth != null) && auth.isEnabled()) 1054 return openConnection(url, auth.getLogin(), auth.getPassword(), disableCache, displayError); 1055 1056 return openConnection(url, null, null, disableCache, displayError); 1057 } 1058 1059 /** 1060 * Returns a new {@link URLConnection} from specified URL (null if an error occurred). 1061 * 1062 * @param url 1063 * url to connect. 1064 * @param disableCache 1065 * Disable proxy cache if any. 1066 * @param displayError 1067 * Display error message in console if something wrong happen. 1068 */ 1069 public static URLConnection openConnection(URL url, boolean disableCache, boolean displayError) 1070 { 1071 return openConnection(url, null, null, disableCache, displayError); 1072 } 1073 1074 /** 1075 * Returns a new {@link URLConnection} from specified path.<br> 1076 * Returns <code>null</code> if an error occurred. 1077 * 1078 * @param path 1079 * path to connect. 1080 * @param disableCache 1081 * Disable proxy cache if any. 1082 * @param displayError 1083 * Display error message in console if something wrong happen. 1084 */ 1085 public static URLConnection openConnection(String path, boolean disableCache, boolean displayError) 1086 { 1087 return openConnection(URLUtil.getURL(path), disableCache, displayError); 1088 } 1089 1090 /** 1091 * Connect the specified {@link URLConnection}.<br> 1092 * Returns false if the connection failed or if response code is not ok. 1093 * 1094 * @param uc 1095 * URLConnection to connect. 1096 * @param displayError 1097 * Display error message in console if something wrong happen. 1098 */ 1099 public static boolean connect(URLConnection uc, boolean displayError) 1100 { 1101 try 1102 { 1103 // final URL prevUrl = uc.getURL(); 1104 1105 // connect 1106 uc.connect(); 1107 1108 // // we have to test that as sometime url are automatically modified / fixed by host! 1109 // if (!uc.getURL().toString().toLowerCase().equals(prevUrl.toString().toLowerCase())) 1110 // { 1111 // // TODO : do something better 1112 // System.out.println("Host URL change rejected : " + prevUrl + " --> " + uc.getURL()); 1113 // return false; 1114 // } 1115 1116 // we test response code for HTTP connection 1117 if (uc instanceof HttpURLConnection) 1118 { 1119 final HttpURLConnection huc = (HttpURLConnection) uc; 1120 1121 // not ok ? 1122 if (huc.getResponseCode() >= 0x400) 1123 { 1124 if (displayError) 1125 { 1126 System.out.println("NetworkUtil.connect('" + huc.getURL() + "' error:"); 1127 System.out.println(huc.getResponseMessage()); 1128 } 1129 1130 return false; 1131 } 1132 } 1133 } 1134 catch (Exception e) 1135 { 1136 if (displayError) 1137 { 1138 if (uc.getURL().getProtocol().equalsIgnoreCase("file")) 1139 IcyExceptionHandler.showErrorMessage(e, false, false); 1140 else 1141 { 1142 if (!hasInternetAccess()) 1143 System.out.println("Can't connect to '" + uc.getURL() + "' (no internet connection)."); 1144 else 1145 { 1146 // HTTPS not supported while we have a HTTPS connection to icy web site 1147 if (!isHTTPSSupported() && uc.getURL().toString().toLowerCase().startsWith("https://icy")) 1148 { 1149 System.err.println("NetworkUtil.connect('" + uc.getURL() 1150 + "') error: HTTPS connection not supported (see detail below)."); 1151 IcyExceptionHandler.showErrorMessage(e, false, false); 1152 } 1153 else 1154 { 1155 System.out.println("NetworkUtil.connect('" + uc.getURL() + "' error:"); 1156 IcyExceptionHandler.showErrorMessage(e, false, false); 1157 } 1158 } 1159 } 1160 } 1161 1162 return false; 1163 } 1164 1165 return true; 1166 } 1167 1168 /** 1169 * Returns a new {@link InputStream} from specified {@link URLConnection} (null if an error 1170 * occurred). 1171 * 1172 * @param uc 1173 * URLConnection object. 1174 * @param displayError 1175 * Display error message in console if something wrong happen. 1176 */ 1177 public static InputStream getInputStream(URLConnection uc, boolean displayError) 1178 { 1179 if (uc == null) 1180 { 1181 if (displayError) 1182 { 1183 System.out.print("NetworkUtil.getInputStream(URLConnection uc) error: URLConnection object is null !"); 1184 } 1185 1186 return null; 1187 } 1188 1189 try 1190 { 1191 return uc.getInputStream(); 1192 } 1193 catch (IOException e) 1194 { 1195 if (displayError) 1196 { 1197 if (!hasInternetAccess()) 1198 System.out.println("Can't connect to '" + uc.getURL() + "' (no internet connection)."); 1199 // HTTPS not supported while we have a HTTPS connection to icy web site 1200 else if (!isHTTPSSupported() && (uc != null) 1201 && uc.getURL().toString().toLowerCase().startsWith("https://icy")) 1202 { 1203 System.err.println("NetworkUtil.getInputStream('" + uc.getURL() 1204 + "') error: HTTPS connection not supported !"); 1205 IcyExceptionHandler.showErrorMessage(e, false, false); 1206 } 1207 else 1208 { 1209 System.out.println("NetworkUtil.getInputStream('" + uc.getURL() + "') error:"); 1210 IcyExceptionHandler.showErrorMessage(e, false, false); 1211 } 1212 } 1213 1214 return null; 1215 } 1216 } 1217 1218 /** 1219 * Returns a new {@link InputStream} from specified URL (null if an error occurred). 1220 * 1221 * @param url 1222 * url we want to connect and retrieve the InputStream. 1223 * @param login 1224 * login if the connection requires authentication.<br> 1225 * Set it to null if no authentication needed. 1226 * @param pass 1227 * login if the connection requires authentication. 1228 * Set it to null if no authentication needed. 1229 * @param disableCache 1230 * Disable proxy cache if any. 1231 * @param displayError 1232 * Display error message in console if something wrong happen. 1233 */ 1234 public static InputStream getInputStream(URL url, String login, String pass, boolean disableCache, 1235 boolean displayError) 1236 { 1237 final URLConnection uc = openConnection(url, login, pass, disableCache, true, displayError); 1238 1239 if (uc != null) 1240 return getInputStream(uc, displayError); 1241 1242 return null; 1243 } 1244 1245 /** 1246 * Returns a new {@link InputStream} from specified URL (null if an error occurred). 1247 * 1248 * @param url 1249 * url we want to connect and retrieve the InputStream. 1250 * @param auth 1251 * Authentication informations. 1252 * @param disableCache 1253 * Disable proxy cache if any. 1254 * @param displayError 1255 * Display error message in console if something wrong happen. 1256 */ 1257 public static InputStream getInputStream(URL url, AuthenticationInfo auth, boolean disableCache, 1258 boolean displayError) 1259 { 1260 if ((auth != null) && (auth.isEnabled())) 1261 return getInputStream(url, auth.getLogin(), auth.getPassword(), disableCache, displayError); 1262 1263 return getInputStream(url, null, null, disableCache, displayError); 1264 } 1265 1266 public static void disableCache(URLConnection uc) 1267 { 1268 uc.setDefaultUseCaches(false); 1269 uc.setUseCaches(false); 1270 uc.setRequestProperty("Cache-Control", "no-cache"); 1271 uc.setRequestProperty("Pragma", "no-cache"); 1272 } 1273 1274 /** 1275 * Process authentication on specified {@link URLConnection} with specified login and pass. 1276 */ 1277 public static void setAuthentication(URLConnection uc, String login, String pass) 1278 { 1279 final String req = login + ":" + pass; 1280 final String encoded; 1281 1282 if (SystemUtil.getJavaVersionAsNumber() >= 8d) 1283 encoded = java.util.Base64.getEncoder().encodeToString(req.getBytes()); 1284 else 1285 encoded = new sun.misc.BASE64Encoder().encode(req.getBytes()); 1286 1287 uc.setRequestProperty("Authorization", "Basic " + encoded); 1288 } 1289 1290 public static String getContentString(Map<String, String> values) 1291 { 1292 String result = ""; 1293 1294 for (Entry<String, String> entry : values.entrySet()) 1295 { 1296 try 1297 { 1298 final String key = entry.getKey(); 1299 1300 if (!StringUtil.isEmpty(key)) 1301 { 1302 final String value = entry.getValue(); 1303 1304 result += "&" + URLEncoder.encode(key, "UTF-8") + "="; 1305 1306 if (!StringUtil.isEmpty(value)) 1307 result += URLEncoder.encode(value, "UTF-8"); 1308 } 1309 } 1310 catch (UnsupportedEncodingException e) 1311 { 1312 // no encoding 1313 result += "&" + entry.getKey() + "=" + entry.getValue(); 1314 } 1315 } 1316 1317 // remove the initial "&" character 1318 return result.substring(1); 1319 } 1320 1321 public static String postData(String target, Map<String, String> values, String login, String pass) 1322 throws IOException 1323 { 1324 return postData(target, getContentString(values), login, pass); 1325 } 1326 1327 public static String postData(String target, String content, String login, String pass) throws IOException 1328 { 1329 String response = ""; 1330 1331 final URLConnection uc = openConnection(target, true, true); 1332 1333 if (uc == null) 1334 return null; 1335 1336 // set connection parameters 1337 uc.setDoInput(true); 1338 uc.setDoOutput(true); 1339 1340 // authentication needed ? 1341 if (login != null) 1342 setAuthentication(uc, login, pass); 1343 1344 // make server believe we are form data... 1345 uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 1346 1347 final DataOutputStream out = new DataOutputStream(uc.getOutputStream()); 1348 try 1349 { 1350 // write out the bytes of the content string to the stream 1351 out.writeBytes(content); 1352 out.flush(); 1353 } 1354 finally 1355 { 1356 out.close(); 1357 } 1358 1359 // read response from the input stream. 1360 final InputStream inStream = getInputStream(uc, false); 1361 if (inStream == null) 1362 return null; 1363 1364 final BufferedReader in = new BufferedReader(new InputStreamReader(inStream)); 1365 1366 try 1367 { 1368 String temp; 1369 while ((temp = in.readLine()) != null) 1370 response += temp + "\n"; 1371 } 1372 finally 1373 { 1374 in.close(); 1375 } 1376 1377 return response; 1378 } 1379 1380 public static String postData(String target, Map<String, String> values) throws IOException 1381 { 1382 return postData(target, values, null, null); 1383 } 1384 1385 public static String postData(String target, String content) throws IOException 1386 { 1387 return postData(target, content, null, null); 1388 } 1389 1390 /** 1391 * Send report (asynchronous processing)<br> 1392 * 1393 * @param values 1394 * list of <key,value> 1395 */ 1396 public static void report(final Map<String, String> values) 1397 { 1398 ThreadUtil.bgRun(new Runnable() 1399 { 1400 @Override 1401 public void run() 1402 { 1403 try 1404 { 1405 if (postData(REPORT_URL, values) == null) 1406 System.out.println("Error while reporting data, verifying your internet connection."); 1407 } 1408 catch (IOException e) 1409 { 1410 System.out.println("Error while reporting data :"); 1411 IcyExceptionHandler.showErrorMessage(e, false, false); 1412 } 1413 } 1414 }); 1415 } 1416 1417 /** 1418 * @deprecated Use {@link #getContentString(Map)} instead. 1419 */ 1420 @Deprecated 1421 public static String getContentString(HashMap<String, String> values) 1422 { 1423 return getContentString((Map<String, String>) values); 1424 } 1425 1426 /** 1427 * @deprecated Use {@link #postData(String, Map, String, String)} instead. 1428 */ 1429 @Deprecated 1430 public static String postData(String target, HashMap<String, String> values, String login, String pass) 1431 throws IOException 1432 { 1433 return postData(target, (Map<String, String>) values, login, pass); 1434 } 1435 1436 /** 1437 * @deprecated Use {@link #postData(String, Map)} instead. 1438 */ 1439 @Deprecated 1440 public static String postData(String target, HashMap<String, String> values) throws IOException 1441 { 1442 return postData(target, (Map<String, String>) values); 1443 } 1444 1445 /** 1446 * @deprecated Use {@link #report(Map)} instead. 1447 */ 1448 @Deprecated 1449 public static void report(final HashMap<String, String> values) 1450 { 1451 report((Map<String, String>) values); 1452 } 1453 1454 public static void enableSystemProxy() 1455 { 1456 SystemUtil.setProperty("java.net.useSystemProxies", "true"); 1457 } 1458 1459 public static void disableSystemProxy() 1460 { 1461 SystemUtil.setProperty("java.net.useSystemProxies", "false"); 1462 } 1463 1464 public static void enableProxySetting() 1465 { 1466 SystemUtil.setProperty("proxySet", "true"); 1467 } 1468 1469 public static void disableProxySetting() 1470 { 1471 SystemUtil.setProperty("proxySet", "false"); 1472 } 1473 1474 public static void enableHTTPProxySetting() 1475 { 1476 SystemUtil.setProperty("http.proxySet", "true"); 1477 } 1478 1479 public static void disableHTTPProxySetting() 1480 { 1481 SystemUtil.setProperty("http.proxySet", "false"); 1482 } 1483 1484 public static void enableHTTPSProxySetting() 1485 { 1486 SystemUtil.setProperty("https.proxySet", "true"); 1487 } 1488 1489 public static void disableHTTPSProxySetting() 1490 { 1491 SystemUtil.setProperty("https.proxySet", "false"); 1492 } 1493 1494 public static void enableFTPProxySetting() 1495 { 1496 SystemUtil.setProperty("ftp.proxySet", "true"); 1497 } 1498 1499 public static void disableFTPProxySetting() 1500 { 1501 SystemUtil.setProperty("ftp.proxySet", "false"); 1502 } 1503 1504 public static void enableSOCKSProxySetting() 1505 { 1506 SystemUtil.setProperty("socksProxySet", "true"); 1507 } 1508 1509 public static void disableSOCKSProxySetting() 1510 { 1511 SystemUtil.setProperty("socksProxySet", "false"); 1512 } 1513 1514 public static void setProxyHost(String host) 1515 { 1516 SystemUtil.setProperty("proxy.server", host); 1517 } 1518 1519 public static void setProxyPort(int port) 1520 { 1521 SystemUtil.setProperty("proxy.port", Integer.toString(port)); 1522 } 1523 1524 public static void setHTTPProxyHost(String host) 1525 { 1526 SystemUtil.setProperty("http.proxyHost", host); 1527 } 1528 1529 public static void setHTTPProxyPort(int port) 1530 { 1531 SystemUtil.setProperty("http.proxyPort", Integer.toString(port)); 1532 } 1533 1534 public static void setHTTPProxyUser(String user) 1535 { 1536 SystemUtil.setProperty("http.proxyUser", user); 1537 } 1538 1539 public static void setHTTPProxyPassword(String password) 1540 { 1541 SystemUtil.setProperty("http.proxyPassword", password); 1542 } 1543 1544 public static void setHTTPSProxyHost(String host) 1545 { 1546 SystemUtil.setProperty("https.proxyHost", host); 1547 } 1548 1549 public static void setHTTPSProxyPort(int port) 1550 { 1551 SystemUtil.setProperty("https.proxyPort", Integer.toString(port)); 1552 } 1553 1554 public static void setHTTPSProxyUser(String user) 1555 { 1556 SystemUtil.setProperty("https.proxyUser", user); 1557 } 1558 1559 public static void setHTTPSProxyPassword(String password) 1560 { 1561 SystemUtil.setProperty("https.proxyPassword", password); 1562 } 1563 1564 public static void setFTPProxyHost(String host) 1565 { 1566 SystemUtil.setProperty("ftp.proxyHost", host); 1567 } 1568 1569 public static void setFTPProxyPort(int port) 1570 { 1571 SystemUtil.setProperty("ftp.proxyPort", Integer.toString(port)); 1572 } 1573 1574 public static void setFTPProxyUser(String user) 1575 { 1576 SystemUtil.setProperty("ftp.proxyUser", user); 1577 } 1578 1579 public static void setFTPProxyPassword(String password) 1580 { 1581 SystemUtil.setProperty("ftp.proxyPassword", password); 1582 } 1583 1584 public static void setSOCKSProxyHost(String host) 1585 { 1586 SystemUtil.setProperty("socksProxyHost", host); 1587 } 1588 1589 public static void setSOCKSProxyPort(int port) 1590 { 1591 SystemUtil.setProperty("socksProxyPort", Integer.toString(port)); 1592 } 1593 1594 public static void setSOCKSProxyUser(String user) 1595 { 1596 SystemUtil.setProperty("socksProxyUser", user); 1597 } 1598 1599 public static void setSOCKSProxyPassword(String password) 1600 { 1601 SystemUtil.setProperty("socksProxyPassword", password); 1602 } 1603 1604 public static String getProxyHost() 1605 { 1606 return SystemUtil.getProperty("proxy.server"); 1607 } 1608 1609 public static int getProxyPort() 1610 { 1611 try 1612 { 1613 return Integer.parseInt(SystemUtil.getProperty("proxy.port")); 1614 } 1615 catch (NumberFormatException e) 1616 { 1617 return 0; 1618 } 1619 } 1620 1621 public static String getHTTPProxyHost() 1622 { 1623 return SystemUtil.getProperty("http.proxyHost"); 1624 } 1625 1626 public static int getHTTPProxyPort() 1627 { 1628 try 1629 { 1630 return Integer.parseInt(SystemUtil.getProperty("http.proxyPort")); 1631 } 1632 catch (NumberFormatException e) 1633 { 1634 return 0; 1635 } 1636 } 1637 1638 public static String getHTTPSProxyHost() 1639 { 1640 return SystemUtil.getProperty("https.proxyHost"); 1641 } 1642 1643 public static int getHTTPSProxyPort() 1644 { 1645 try 1646 { 1647 return Integer.parseInt(SystemUtil.getProperty("https.proxyPort")); 1648 } 1649 catch (NumberFormatException e) 1650 { 1651 return 0; 1652 } 1653 } 1654 1655 public static String getFTPProxyHost() 1656 { 1657 return SystemUtil.getProperty("ftp.proxyHost"); 1658 } 1659 1660 public static int getFTPProxyPort() 1661 { 1662 try 1663 { 1664 return Integer.parseInt(SystemUtil.getProperty("ftp.proxyPort")); 1665 } 1666 catch (NumberFormatException e) 1667 { 1668 return 0; 1669 } 1670 } 1671 1672 public static String getSOCKSProxyHost() 1673 { 1674 return SystemUtil.getProperty("socksProxyHost"); 1675 } 1676 1677 public static int getSOCKSProxyPort() 1678 { 1679 try 1680 { 1681 return Integer.parseInt(SystemUtil.getProperty("socksProxyPort")); 1682 } 1683 catch (NumberFormatException e) 1684 { 1685 return 0; 1686 } 1687 } 1688 1689}