X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FDownloader.java;h=4191d0aea0da85511e2741c50c2a6c83806f612f;hp=4976c483aef7ab8be33fb21ee757f205b13b292f;hb=e14f67abf357c8db74aa230faf8922f93f59c7d6;hpb=3052163b494bf89d178638a047ca80008578a782 diff --git a/src/be/nikiroo/utils/Downloader.java b/src/be/nikiroo/utils/Downloader.java index 4976c48..4191d0a 100644 --- a/src/be/nikiroo/utils/Downloader.java +++ b/src/be/nikiroo/utils/Downloader.java @@ -30,6 +30,7 @@ public class Downloader { private CookieManager cookies; private TraceHandler tracer = new TraceHandler(); private Cache cache; + private boolean offline; /** * Create a new {@link Downloader}. @@ -38,7 +39,7 @@ public class Downloader { * the User-Agent to use to download the resources -- note that * some websites require one, some actively blacklist real UAs * like the one from wget, some whitelist a couple of browsers - * only (!) + * only (!) -- can be NULL */ public Downloader(String UA) { this(UA, null); @@ -51,18 +52,43 @@ public class Downloader { * the User-Agent to use to download the resources -- note that * some websites require one, some actively blacklist real UAs * like the one from wget, some whitelist a couple of browsers - * only (!) + * only (!) -- can be NULL * @param cache * the {@link Cache} to use for all access (can be NULL) */ public Downloader(String UA, Cache cache) { this.UA = UA; - cookies = new CookieManager(); - cookies.setCookiePolicy(CookiePolicy.ACCEPT_ALL); + cookies = new CookieManager(null, CookiePolicy.ACCEPT_ALL); CookieHandler.setDefault(cookies); - this.cache = cache; + setCache(cache); + } + + /** + * This {@link Downloader} is forbidden to try and connect to the network. + *

+ * If TRUE, it will only check the cache if any. + *

+ * Default is FALSE. + * + * @return TRUE if offline + */ + public boolean isOffline() { + return offline; + } + + /** + * This {@link Downloader} is forbidden to try and connect to the network. + *

+ * If TRUE, it will only check the cache if any. + *

+ * Default is FALSE. + * + * @param offline TRUE for offline, FALSE for online + */ + public void setOffline(boolean offline) { + this.offline = offline; } /** @@ -168,7 +194,7 @@ public class Downloader { * @return the {@link InputStream} of the opened page * * @throws IOException - * in case of I/O error + * in case of I/O error (including offline mode + not in cache) */ public InputStream open(URL url, URL currentReferer, Map cookiesValues, Map postParams, @@ -200,7 +226,7 @@ public class Downloader { * @return the {@link InputStream} of the opened page * * @throws IOException - * in case of I/O error + * in case of I/O error (including offline mode + not in cache) */ public InputStream open(URL url, URL currentReferer, Map cookiesValues, Map postParams, @@ -216,7 +242,13 @@ public class Downloader { * @param url * the {@link URL} to open * @param originalUrl - * the original {@link URL} before any redirection occurs + * the original {@link URL} before any redirection occurs, which + * is also used for the cache ID if needed (so we can retrieve + * the content with this URL if needed) + * @param currentReferer + * the current referer, for websites that needs this info + * @param cookiesValues + * the cookies * @param postParams * the POST parameters * @param getParams @@ -231,23 +263,31 @@ public class Downloader { * @return the {@link InputStream} of the opened page * * @throws IOException - * in case of I/O error + * in case of I/O error (including offline mode + not in cache) */ - private InputStream open(URL url, final URL originalUrl, - URL currentReferer, Map cookiesValues, - Map postParams, Map getParams, - String oauth, boolean stable) throws IOException { + public InputStream open(URL url, final URL originalUrl, URL currentReferer, + Map cookiesValues, Map postParams, + Map getParams, String oauth, boolean stable) + throws IOException { tracer.trace("Request: " + url); if (cache != null) { - InputStream in = cache.load(url, false, stable); + InputStream in = cache.load(originalUrl, false, stable); if (in != null) { - tracer.trace("Take from cache: " + url); + tracer.trace("Use the cache: " + url); + tracer.trace("Original URL : " + originalUrl); return in; } } + String protocol = originalUrl == null ? null : originalUrl + .getProtocol(); + if (isOffline() && !"file".equalsIgnoreCase(protocol)) { + tracer.error("Downloader OFFLINE, cannot proceed to URL: " + url); + throw new IOException("Downloader is currently OFFLINE, cannot download: " + url); + } + tracer.trace("Download: " + url); URLConnection conn = openConnectionWithCookies(url, currentReferer, @@ -259,9 +299,9 @@ public class Downloader { params = postParams; } + StringBuilder requestData = null; if ((params != null || oauth != null) && conn instanceof HttpURLConnection) { - StringBuilder requestData = null; if (params != null) { requestData = new StringBuilder(); for (Map.Entry param : params.entrySet()) { @@ -274,15 +314,14 @@ public class Downloader { String.valueOf(param.getValue()), "UTF-8")); } - conn.setDoOutput(true); - if (getParams == null && postParams != null) { ((HttpURLConnection) conn).setRequestMethod("POST"); } conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("charset", "utf-8"); + conn.setRequestProperty("Content-Length", + Integer.toString(requestData.length())); } if (oauth != null) { @@ -290,22 +329,28 @@ public class Downloader { } if (requestData != null) { - OutputStreamWriter writer = null; + conn.setDoOutput(true); + OutputStreamWriter writer = new OutputStreamWriter( + conn.getOutputStream()); try { - writer = new OutputStreamWriter(conn.getOutputStream()); writer.write(requestData.toString()); writer.flush(); } finally { - if (writer != null) { - writer.close(); - } + writer.close(); } } } + // Manual redirection, much better for POST data + if (conn instanceof HttpURLConnection) { + ((HttpURLConnection) conn).setInstanceFollowRedirects(false); + } + conn.connect(); // Check if redirect + // BEWARE! POST data cannot be redirected (some webservers complain) for + // HTTP codes 302 and 303 if (conn instanceof HttpURLConnection) { int repCode = 0; try { @@ -317,27 +362,53 @@ public class Downloader { if (repCode / 100 == 3) { String newUrl = conn.getHeaderField("Location"); return open(new URL(newUrl), originalUrl, currentReferer, - cookiesValues, postParams, getParams, oauth, stable); + cookiesValues, // + (repCode == 302 || repCode == 303) ? null : postParams, // + getParams, oauth, stable); } } - InputStream in = conn.getInputStream(); - if ("gzip".equals(conn.getContentEncoding())) { - in = new GZIPInputStream(in); - } + try { + InputStream in = conn.getInputStream(); + if ("gzip".equals(conn.getContentEncoding())) { + in = new GZIPInputStream(in); + } - if (in != null && cache != null) { - tracer.trace("Save to cache: " + url); - try { - cache.save(in, url); - } catch (IOException e) { - tracer.error(new IOException( - "Cannot save URL to cache, will ignore cache: " + url, - e)); + if (in == null) { + throw new IOException("No InputStream!"); } - } - return in; + if (cache != null) { + String size = conn.getContentLength() < 0 ? "unknown size" + : StringUtils.formatNumber(conn.getContentLength()) + + "bytes"; + tracer.trace("Save to cache (" + size + "): " + originalUrl); + try { + try { + long bytes = cache.save(in, originalUrl); + tracer.trace("Saved to cache: " + + StringUtils.formatNumber(bytes) + "bytes"); + } finally { + in.close(); + } + in = cache.load(originalUrl, true, true); + } catch (IOException e) { + tracer.error(new IOException( + "Cannot save URL to cache, will ignore cache: " + + url, e)); + } + } + + if (in == null) { + throw new IOException( + "Cannot retrieve the file after storing it in the cache (??)"); + } + + return in; + } catch (IOException e) { + throw new IOException(String.format( + "Cannot find %s (current URL: %s)", originalUrl, url), e); + } } /** @@ -357,9 +428,18 @@ public class Downloader { throws IOException { URLConnection conn = url.openConnection(); - conn.setRequestProperty("User-Agent", UA); - conn.setRequestProperty("Cookie", generateCookies(cookiesValues)); + String cookies = generateCookies(cookiesValues); + if (cookies != null && !cookies.isEmpty()) { + conn.setRequestProperty("Cookie", cookies); + } + + if (UA != null) { + conn.setRequestProperty("User-Agent", UA); + } conn.setRequestProperty("Accept-Encoding", "gzip"); + conn.setRequestProperty("Accept", "*/*"); + conn.setRequestProperty("Charset", "utf-8"); + if (currentReferer != null) { conn.setRequestProperty("Referer", currentReferer.toString()); conn.setRequestProperty("Host", currentReferer.getHost()); @@ -381,7 +461,6 @@ public class Downloader { builder.append(';'); } - // TODO: check if format is ok builder.append(cookie.toString()); }