/** * xweb project * Created by Hamed Abdollahpour * http://www.mobile4use.com/xweb */ package ir.xweb.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.*; import java.util.ArrayList; import java.util.List; public class Downloader { private final String DEFAULT_USER_AGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"; private final URL url; private int retry = 0; private int timout; private int maxSize; private Proxy proxy; private String userAgent; private List<String> mimeTypes; public Downloader(final String url) { try { this.url = new URL(url); } catch (MalformedURLException ex) { throw new IllegalArgumentException(ex); } } public Downloader(final URL url) { this.url = url; } public Downloader retry(final int count) { this.retry = count; return this; } /** * Set connection timeout. Remember that timeout can apply after resolve name server by DNS. So. if this process * take a long time not error happens. (But there's a default timeout for name server resolving also in most of * JREs implementations) * @param millis * @return */ public Downloader timeout(final int millis) { this.timout = millis; return this; } public Downloader maxSize(final int size) { this.maxSize = size; return this; } /** * You can get list of available UserAgents at <a href='http://www.useragentstring.com/pages/useragentstring.php'>www.useragentstring.com</a> * @param userAgent User agent for downloader * @return */ public Downloader userAgent(final String userAgent) { this.userAgent = userAgent; return this; } /** * Set proxy with URI. For http proxy http://hostname:port or https://hostname:port for socket proxy host:port. * @param uri Proxy URI. Null URI will be ignore * @return */ public Downloader proxy(final String uri) { if(uri != null) { if(uri.startsWith("http")) { try { final URI u = new URI(uri); this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(u.getHost(), u.getPort())); } catch (URISyntaxException ex) { throw new IllegalArgumentException(ex); } } else { final String[] parts = uri.split(":"); if(parts.length == 2) { this.proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(parts[0], Integer.parseInt(parts[1]))); } else { throw new IllegalArgumentException("Illegal URI: " + uri); } } } return this; } public Downloader mimeType(String... mimetypes) { if(this.mimeTypes == null) { this.mimeTypes = new ArrayList<String>(); } this.mimeTypes.addAll(mimeTypes); return this; } public Downloader httpProxy(final String host, final int port) { if(host == null) { throw new IllegalArgumentException("null host"); } if(port <= 0) { throw new IllegalArgumentException("illegal port: " + port); } this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); return this; } public Downloader socketProxy(final String host, final int port) { if(host == null) { throw new IllegalArgumentException("null host"); } if(port <= 0) { throw new IllegalArgumentException("illegal port: " + port); } this.proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(host, port)); return this; } public InputStream openStream() throws IOException { int r = this.retry; do { try { final URLConnection conn = (proxy == null ? this.url.openConnection() : this.url.openConnection(proxy)); if(this.timout > 0) { conn.setConnectTimeout(this.timout); conn.setReadTimeout(this.timout); } conn.addRequestProperty("User-Agent", userAgent == null ? DEFAULT_USER_AGENT : userAgent); if(maxSize > 0) { final String contentLength = conn.getHeaderField("Content-Length"); if(contentLength != null) { if(Integer.parseInt(contentLength) > maxSize) { throw new IllegalStateException("Illegal size: " + contentLength + " > " + maxSize); } } } return conn.getInputStream(); } catch (SocketTimeoutException ex) { if(r > 0) { r--; } else { throw ex; } } } while (r > -1); throw new SocketTimeoutException(); } public byte[] download() throws IOException { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); int r = this.retry; InputStream is = null; do { try { final HttpURLConnection conn = (HttpURLConnection)(proxy == null ? this.url.openConnection() : this.url.openConnection(proxy)); if(this.timout > 0) { conn.setConnectTimeout(this.timout); conn.setReadTimeout(this.timout); } final String contentLength = conn.getRequestProperty("Content-Length"); final String acceptRanges = conn.getRequestProperty("Accept-Ranges"); final String mimeType = conn.getRequestProperty("Content-Type"); if(mimeTypes != null && mimeTypes.size() > 0) { if(mimeTypes.contains(mimeType)) { throw new MimeTypeNotFoundException(mimeType + " is not right for: " + url); } } if(contentLength != null && maxSize > 0) { if(Integer.parseInt(contentLength) > maxSize) { throw new IllegalStateException("Illegal size: " + contentLength + " > " + maxSize); } } conn.addRequestProperty("User-Agent", userAgent == null ? DEFAULT_USER_AGENT : userAgent); if(baos.size() > 0 && acceptRanges != null && acceptRanges.contains("bytes")){ conn.setRequestProperty("Range", "bytes=" + baos.size() + "-"); } else { baos.reset(); } if(conn.getResponseCode() == 200) { is = conn.getInputStream(); int size; byte[] buffer = new byte[10240]; while ((size = is.read(buffer)) > 0) { if (maxSize > 0 && size + baos.size() > maxSize) { throw new IllegalStateException("Size is more that max size"); } baos.write(buffer, 0, size); } return baos.toByteArray(); } return null; } catch (SocketTimeoutException ex) { if(r > 0) { r--; } else { throw ex; } } finally { if(is != null) { try { is.close(); } catch (Exception ex) {} } } } while (r > 0); throw new SocketTimeoutException(); } public class MimeTypeNotFoundException extends IOException { public MimeTypeNotFoundException(final String message) { super(message); } } }