package net.vhati.modmanager.json; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class URLFetcher { private static final Logger log = LogManager.getLogger(URLFetcher.class); /** * Downloads content from a url into a file, if the remote content has changed. * * @return true if successfully downloaded, false otherwise */ public static boolean refetchURL( String url, File localFile, File eTagFile ) { String localETag = null; log.debug( String.format( "Attempting to download the latest \"%s\".", localFile.getName() ) ); if ( eTagFile.exists() ) { // Load the old eTag. InputStream etagIn = null; try { etagIn = new FileInputStream( eTagFile ); BufferedReader br = new BufferedReader( new InputStreamReader( etagIn, "UTF-8" ) ); String line = br.readLine(); if ( line.length() > 0 ) localETag = line; } catch ( IOException e ) { // Not serious enough to be a real error. log.debug( String.format( "Error reading eTag from \"%s\".", eTagFile.getName() ), e ); } finally { try {if ( etagIn != null ) etagIn.close();} catch ( IOException e ) {} } } String remoteETag = null; InputStream urlIn = null; OutputStream localOut = null; try { URLConnection conn = new URL( url ).openConnection(); if ( conn instanceof HttpURLConnection == false ) { log.error( String.format( "Non-Http(s) URL given for fetching: %s", url ) ); return false; } HttpURLConnection httpConn = (HttpURLConnection)conn; httpConn.setReadTimeout( 10000 ); if ( localETag != null ) httpConn.setRequestProperty( "If-None-Match", localETag ); httpConn.connect(); int responseCode = httpConn.getResponseCode(); if ( responseCode == HttpURLConnection.HTTP_NOT_MODIFIED ) { log.debug( String.format( "No need to update \"%s\", the server's copy has not been modified since the previous check.", localFile.getName() ) ); // Update the local file's timestamp as if it had downloaded. localFile.setLastModified( new Date().getTime() ); return false; } else if ( responseCode == HttpURLConnection.HTTP_OK ) { Map<String, List<String>> headerMap = httpConn.getHeaderFields(); List<String> eTagValues = headerMap.get( "ETag" ); if ( eTagValues != null && eTagValues.size() > 0 ) remoteETag = eTagValues.get( 0 ); urlIn = httpConn.getInputStream(); localOut = new FileOutputStream( localFile ); byte[] buf = new byte[4096]; int len; while ( (len = urlIn.read(buf)) >= 0 ) { localOut.write( buf, 0, len ); } } else { log.error( String.format( "Download request failed for \"%s\": HTTP Code %d (%s).", httpConn.getURL(), responseCode, httpConn.getResponseMessage() ) ); return false; } } catch ( IOException e ) { log.error( String.format( "Error downloading the latest \"%s\".", localFile.getName() ), e ); } finally { try {if ( urlIn != null ) urlIn.close();} catch ( IOException e ) {} try {if ( localOut != null ) localOut.close();} catch ( IOException e ) {} } if ( remoteETag != null ) { // Save the new eTag. OutputStream etagOut = null; try { etagOut = new FileOutputStream( eTagFile ); BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( etagOut, "UTF-8" ) ); bw.append( remoteETag ); bw.flush(); } catch ( IOException e ) { log.error( String.format( "Error writing eTag to \"%s\".", eTagFile.getName() ), e ); } finally { try {if ( etagOut != null ) etagOut.close();} catch ( IOException e ) {} } } return true; } }