View Javadoc

    1   /*
    2    * This file is part of dependency-check-core.
    3    *
    4    * Dependency-check-core is free software: you can redistribute it and/or modify it
    5    * under the terms of the GNU General Public License as published by the Free
    6    * Software Foundation, either version 3 of the License, or (at your option) any
    7    * later version.
    8    *
    9    * Dependency-check-core is distributed in the hope that it will be useful, but
    10   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
    12   * details.
    13   *
    14   * You should have received a copy of the GNU General Public License along with
    15   * dependency-check-core. If not, see http://www.gnu.org/licenses/.
    16   *
    17   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
    18   */
    19  package org.owasp.dependencycheck.utils;
    20
    21  import java.io.BufferedOutputStream;
    22  import java.io.File;
    23  import java.io.FileOutputStream;
    24  import java.io.IOException;
    25  import java.io.InputStream;
    26  import java.net.Authenticator;
    27  import java.net.HttpURLConnection;
    28  import java.net.InetSocketAddress;
    29  import java.net.PasswordAuthentication;
    30  import java.net.Proxy;
    31  import java.net.SocketAddress;
    32  import java.net.URISyntaxException;
    33  import java.net.URL;
    34  import java.util.logging.Level;
    35  import java.util.logging.Logger;
    36  import java.util.zip.GZIPInputStream;
    37  import java.util.zip.InflaterInputStream;
    38
    39  /**
    40   * A utility to download files from the Internet.
    41   *
    42   * @author Jeremy Long (jeremy.long@owasp.org)
    43   */
    44  public final class Downloader {
    45
    46      /**
    47       * Private constructor for utility class.
    48       */
    49      private Downloader() {
    50      }
    51
    52      /**
    53       * Retrieves a file from a given URL and saves it to the outputPath.
    54       *
    55       * @param url the URL of the file to download.
    56       * @param outputPath the path to the save the file to.
    57       * @throws DownloadFailedException is thrown if there is an error
    58       * downloading the file.
    59       */
    60      public static void fetchFile(URL url, File outputPath) throws DownloadFailedException {
    61          HttpURLConnection conn = null;
    62          try {
    63              conn = Downloader.getConnection(url);
    64              conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
    65              conn.connect();
    66          } catch (IOException ex) {
    67              try {
    68                  if (conn != null) {
    69                      conn.disconnect();
    70                  }
    71              } finally {
    72                  conn = null;
    73              }
    74              throw new DownloadFailedException("Error downloading file.", ex);
    75          }
    76          final String encoding = conn.getContentEncoding();
    77
    78          BufferedOutputStream writer = null;
    79          InputStream reader = null;
    80          try {
    81              if (encoding != null && "gzip".equalsIgnoreCase(encoding)) {
    82                  reader = new GZIPInputStream(conn.getInputStream());
    83              } else if (encoding != null && "deflate".equalsIgnoreCase(encoding)) {
    84                  reader = new InflaterInputStream(conn.getInputStream());
    85              } else {
    86                  reader = conn.getInputStream();
    87              }
    88
    89              writer = new BufferedOutputStream(new FileOutputStream(outputPath));
    90              final byte[] buffer = new byte[4096];
    91              int bytesRead;
    92              while ((bytesRead = reader.read(buffer)) > 0) {
    93                  writer.write(buffer, 0, bytesRead);
    94              }
    95          } catch (Exception ex) {
    96              throw new DownloadFailedException("Error saving downloaded file.", ex);
    97          } finally {
    98              if (writer != null) {
    99                  try {
    100                     writer.close();
    101                 } catch (Exception ex) {
    102                     Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
    103                             "Error closing the writer in Downloader.", ex);
    104                 }
    105             }
    106             if (reader != null) {
    107                 try {
    108                     reader.close();
    109                 } catch (Exception ex) {
    110                     Logger.getLogger(Downloader.class.getName()).log(Level.FINEST,
    111                             "Error closing the reader in Downloader.", ex);
    112                 }
    113             }
    114             try {
    115                 conn.disconnect();
    116             } finally {
    117                 conn = null;
    118             }
    119         }
    120     }
    121
    122     /**
    123      * Makes an HTTP Head request to retrieve the last modified date of the
    124      * given URL. If the file:// protocol is specified, then the lastTimestamp
    125      * of the file is returned.
    126      *
    127      * @param url the URL to retrieve the timestamp from
    128      * @return an epoch timestamp
    129      * @throws DownloadFailedException is thrown if an exception occurs making
    130      * the HTTP request
    131      */
    132     public static long getLastModified(URL url) throws DownloadFailedException {
    133         long timestamp = 0;
    134         //TODO add the FPR protocol?
    135         if ("file".equalsIgnoreCase(url.getProtocol())) {
    136             File lastModifiedFile;
    137             try {
    138 //                if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
    139 //                    String filePath = url.toString();
    140 //                    if (filePath.matches("file://[a-zA-Z]:.*")) {
    141 //                        f = new File(filePath.substring(7));
    142 //                    } else {
    143 //                        f = new File(url.toURI());
    144 //                    }
    145 //                } else {
    146                 lastModifiedFile = new File(url.toURI());
    147 //                }
    148             } catch (URISyntaxException ex) {
    149                 final String msg = String.format("Unable to locate '%s'; is the cve.url-2.0.modified property set correctly?", url.toString());
    150                 throw new DownloadFailedException(msg);
    151             }
    152             timestamp = lastModifiedFile.lastModified();
    153         } else {
    154             HttpURLConnection conn = null;
    155             try {
    156                 conn = Downloader.getConnection(url);
    157                 conn.setRequestMethod("HEAD");
    158                 conn.connect();
    159                 timestamp = conn.getLastModified();
    160             } catch (Exception ex) {
    161                 throw new DownloadFailedException("Error making HTTP HEAD request.", ex);
    162             } finally {
    163                 if (conn != null) {
    164                     try {
    165                         conn.disconnect();
    166                     } finally {
    167                         conn = null;
    168                     }
    169                 }
    170             }
    171         }
    172         return timestamp;
    173     }
    174
    175     /**
    176      * Utility method to get an HttpURLConnection. If the app is configured to
    177      * use a proxy this method will retrieve the proxy settings and use them
    178      * when setting up the connection.
    179      *
    180      * @param url the url to connect to
    181      * @return an HttpURLConnection
    182      * @throws DownloadFailedException thrown if there is an exception
    183      */
    184     private static HttpURLConnection getConnection(URL url) throws DownloadFailedException {
    185         HttpURLConnection conn = null;
    186         Proxy proxy = null;
    187         final String proxyUrl = Settings.getString(Settings.KEYS.PROXY_URL);
    188         try {
    189             if (proxyUrl != null) {
    190                 final int proxyPort = Settings.getInt(Settings.KEYS.PROXY_PORT);
    191                 final SocketAddress addr = new InetSocketAddress(proxyUrl, proxyPort);
    192
    193                 final String username = Settings.getString(Settings.KEYS.PROXY_USERNAME);
    194                 final String password = Settings.getString(Settings.KEYS.PROXY_PASSWORD);
    195                 if (username != null && password != null) {
    196                     final Authenticator auth = new Authenticator() {
    197                         @Override
    198                         public PasswordAuthentication getPasswordAuthentication() {
    199                             if (getRequestorType().equals(RequestorType.PROXY)) {
    200                                 return new PasswordAuthentication(username, password.toCharArray());
    201                             }
    202                             return super.getPasswordAuthentication();
    203                         }
    204                     };
    205                     Authenticator.setDefault(auth);
    206                 }
    207
    208                 proxy = new Proxy(Proxy.Type.HTTP, addr);
    209                 conn = (HttpURLConnection) url.openConnection(proxy);
    210             } else {
    211                 conn = (HttpURLConnection) url.openConnection();
    212             }
    213             final int timeout = Settings.getInt(Settings.KEYS.CONNECTION_TIMEOUT, 60000);
    214             conn.setConnectTimeout(timeout);
    215         } catch (IOException ex) {
    216             if (conn != null) {
    217                 try {
    218                     conn.disconnect();
    219                 } finally {
    220                     conn = null;
    221                 }
    222             }
    223             throw new DownloadFailedException("Error getting connection.", ex);
    224         }
    225         return conn;
    226     }
    227 }