protected boolean connectResumable() throws IOException { // TODO: endrange pruefen long[] chunkProgress = downloadLink.getChunksProgress(); String start, end; start = end = ""; boolean rangeRequested = false; logger.info("chunksProgress: " + Arrays.toString(chunkProgress)); if (downloadLink.getVerifiedFileSize() > 0) { start = chunkProgress[0] == 0 ? "0" : (chunkProgress[0] + 1) + ""; end = (getFileSize() / chunkProgress.length) + ""; } else { start = chunkProgress[0] == 0 ? "0" : (chunkProgress[0] + 1) + ""; end = chunkProgress.length > 1 ? (chunkProgress[1] + 1) + "" : ""; } if (downloadLink.getVerifiedFileSize() < 0 && start.equals("0")) { logger.info("rangeless resumable connect"); rangeRequested = false; request.getHeaders().remove("Range"); } else { rangeRequested = true; if (start.equalsIgnoreCase(end)) { logger.info("WTF, start equals end! Workaround: maybe manipulating the startRange?! it's about time for new downloadcore!"); } request.getHeaders().put("Range", "bytes=" + start + "-" + end); } browser.connect(request); return rangeRequested; }
protected void connectFirstRange() throws IOException { long fileSize = getFileSize(); long part = fileSize / this.getChunkNum(); boolean verifiedSize = downloadLink.getVerifiedFileSize() > 0; boolean openRangeRequested = false; if (verifiedSize == false || this.getChunkNum() == 1) { /* we only request a single range */ openRangeRequested = true; /* Workaround for server responses != 206 */ if (this.downloadLink.getBooleanProperty("ServerComaptibleForByteRangeRequest", false)) request.getHeaders().put("Range", "bytes=" + (0) + "-"); } else { /* we request multiple ranges */ openRangeRequested = false; request.getHeaders().put("Range", "bytes=" + (0) + "-" + (part - 1)); } browser.connect(request); if (request.getHttpConnection().getResponseCode() == 416) { logger.warning("HTTP/1.1 416 Requested Range Not Satisfiable"); if (this.plugin.getBrowser().isDebug()) logger.finest("\r\n" + request.printHeaders()); throw new IllegalStateException("HTTP/1.1 416 Requested Range Not Satisfiable"); } else if (request.getHttpConnection().getRange() == null) { logger.warning("No Chunkload"); setChunkNum(1); } else { long[] range = request.getHttpConnection().getRange(); if (range[0] != 0) { /* first range MUST start at zero */ throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + ". Got range: " + request.getHttpConnection().getHeaderField("Content-Range")); } else if (verifiedSize && range[1] < (part - 1)) { /* response range != requested range */ throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range")); } else if (!openRangeRequested && range[1] == range[2] - 1 && getChunkNum() > 1) { logger.warning(" Chunkload Protection.. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range")); setChunkNum(1); } else if (verifiedSize && range[1] > (part - 1)) { /* response range is bigger than requested range */ if (verifiedSize && range[1] == part) { logger.severe("Workaround for buggy http server: rangeEND=contentEND, it must be rangeEND-1=contentEND as 0 is first byte!"); return; } throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range")); } } }
/** * * @param downloadLink * downloadlink der geladne werden soll (wird zur darstellung verwendet) * @param request * Verbindung die geladen werden soll * @param b * Resumefaehige verbindung * @param i * max chunks. fuer negative werte wirden die chunks aus der config verwendet. Bsp: -3 : Min(3,Configwert); * @return * @throws IOException * @throws PluginException */ public static DownloadInterface download(DownloadLink downloadLink, Request request, boolean b, int i) throws IOException, PluginException { /* disable gzip, because current downloadsystem cannot handle it correct */ request.getHeaders().put("Accept-Encoding", null); RAFDownload dl = new RAFDownload(downloadLink.getLivePlugin(), downloadLink, request); PluginForHost plugin = downloadLink.getLivePlugin(); if (plugin != null) plugin.setDownloadInterface(dl); if (i == 0) { dl.setChunkNum(JsonConfig.create(GeneralSettings.class).getMaxChunksPerFile()); } else { dl.setChunkNum(i < 0 ? Math.min(i * -1, JsonConfig.create(GeneralSettings.class).getMaxChunksPerFile()) : i); } dl.setResume(b); return dl; }
public URLConnectionAdapter connect() throws Exception { logger.finer("Connect..."); if (request == null) throw new IllegalStateException("Wrong Mode. Instance is in direct Connection mode"); this.connected = true; boolean resumed = false; if (this.isRangeRequestSupported() && this.checkResumabled()) { /* we can continue to resume the download */ logger.finer(".....connectResumable"); resumed = connectResumable(); } else { long verifiedFileSize = downloadLink.getVerifiedFileSize(); if (verifiedFileSize > 0 && getChunkNum() > 1) { /* check if we have to adapt the number of chunks */ int tmp = Math.min(Math.max(1, (int) (verifiedFileSize / RAFChunk.MIN_CHUNKSIZE)), getChunkNum()); if (tmp != getChunkNum()) { logger.finer("Corrected Chunknum: " + getChunkNum() + " -->" + tmp); setChunkNum(tmp); } } if (this.isRangeRequestSupported()) { /* range requests are supported! */ logger.finer(".....connectFirstRange"); connectFirstRange(); } else { logger.finer(".....connectRangeless"); /* our connection happens rangeless */ request.getHeaders().remove("Range"); /* Workaround for rayfile.com */ if (this.downloadLink.getBooleanProperty("ServerComaptibleForByteRangeRequest", false)) { if ("rayfile.com".contains(this.downloadLink.getHost())) request.getHeaders().put("Range", "bytes=" + (0) + "-"); } browser.connect(request); } } if (this.plugin.getBrowser().isDebug()) logger.finest("\r\n" + request.printHeaders()); connection = request.getHttpConnection(); if (request.getLocation() != null) throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, BrowserAdapter.ERROR_REDIRECTED); if (connection.getRange() != null) { /* we have a range response, let's use it */ if (connection.getRange()[2] > 0) { this.setFilesizeCheck(true); this.downloadLink.setDownloadSize(connection.getRange()[2]); } } else if (resumed == false && connection.getLongContentLength() > 0 && connection.isOK()) { this.setFilesizeCheck(true); this.downloadLink.setDownloadSize(connection.getLongContentLength()); } if (connection.getResponseCode() == 416 && resumed == true && downloadLink.getChunksProgress().length == 1 && downloadLink.getVerifiedFileSize() == downloadLink.getChunksProgress()[0] + 1) { logger.info("Faking Content-Disposition for already finished downloads"); /* we requested a finished loaded file, got 416 and content-range with * and one chunk only */ /* we fake a content disposition connection so plugins work normal */ if (connection.isContentDisposition() == false) { List<String> list = new ArrayList<String>(); list.add("fakeContent"); connection.getHeaderFields().put("Content-Disposition", list); } List<String> list = new ArrayList<String>(); list.add("application/octet-stream"); connection.getHeaderFields().put("Content-Type", list); dlAlreadyFinished = true; } return connection; }