private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); for (String s : response.getHeaderNames()) { for (String header : response.getHeaders(s)) { h.add(s, header); } } if (trailingHeaders != null && trailingHeaders.getHeaderNames().size() > 0) { for (final String s : trailingHeaders.getHeaderNames()) { for (String header : response.getHeaders(s)) { h.add(s, header); } } } return h; }
private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); Header[] uh = method.getResponseHeaders(); for (Header e : uh) { if (e.getName() != null) { h.add(e.getName(), e.getValue()); } } uh = method.getResponseFooters(); for (Header e : uh) { if (e.getName() != null) { h.add(e.getName(), e.getValue()); } } return h; }
public void run() { download.setState(Transfer.State.ACTIVE); final String uri = validateUri(path); final TransferResource transferResource = new DefaultTransferResource(repository.getUrl(), path, file, download.getTrace()); final boolean ignoreChecksum = RepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals(checksumPolicy); CompletionHandler completionHandler = null; final FileLockCompanion fileLockCompanion = (file != null) ? createOrGetTmpFile(file.getPath(), allowResumable) : new FileLockCompanion(null, null); try { long length = 0; if (fileLockCompanion.getFile() != null) { fileProcessor.mkdirs(fileLockCompanion.getFile().getParentFile()); } // Position the file to the end in case we are resuming an aborded download. final RandomAccessFile resumableFile = fileLockCompanion.getFile() == null ? null : new RandomAccessFile(fileLockCompanion.getFile(), "rw"); if (resumableFile != null) { length = resumableFile.length(); } FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); if (!useCache) { headers.add("Pragma", "no-cache"); } headers.add("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"); headers.replaceAll(AsyncRepositoryConnector.this.headers); Request request = null; final AtomicInteger maxRequestTry = new AtomicInteger(); AsyncHttpClient client = httpClient; final AtomicBoolean closeOnComplete = new AtomicBoolean(false); /** * If length > 0, it means we are resuming a interrupted download. If that's the case, we * can't re-use the current httpClient because compression is enabled, and supporting * compression per request is not supported in ahc and may never has it could have a * performance impact. */ if (length > 0) { AsyncHttpClientConfig config = createConfig(session, repository, false); client = new AsyncHttpClient(new NettyAsyncHttpProvider(config)); request = client.prepareGet(uri).setRangeOffset(length).setHeaders(headers).build(); closeOnComplete.set(true); } else { request = httpClient.prepareGet(uri).setHeaders(headers).build(); } final Request activeRequest = request; final AsyncHttpClient activeHttpClient = client; completionHandler = new CompletionHandler(transferResource, httpClient, logger, RequestType.GET) { private final AtomicBoolean seekEndOnFile = new AtomicBoolean(false); private final AtomicBoolean handleTmpFile = new AtomicBoolean(true); private final AtomicBoolean localException = new AtomicBoolean(false); /** {@inheritDoc} */ @Override public STATE onHeadersReceived(final HttpResponseHeaders headers) throws Exception { FluentCaseInsensitiveStringsMap h = headers.getHeaders(); String rangeByteValue = h.getFirstValue("Content-Range"); // Make sure the server acceptance of the range requests headers if (rangeByteValue != null && rangeByteValue.compareToIgnoreCase("none") != 0) { seekEndOnFile.set(true); } return super.onHeadersReceived(headers); } @Override public void onThrowable(Throwable t) { try { logger.debug("onThrowable", t); /** * If an IOException occurs, let's try to resume the request based on how much * bytes has been so far downloaded. Fail after IOException. */ if (!disableResumeSupport && !localException.get() && maxRequestTry.get() < maxIOExceptionRetry && IOException.class.isAssignableFrom(t.getClass())) { logger.debug("Trying to recover from an IOException " + activeRequest); maxRequestTry.incrementAndGet(); Request newRequest = new RequestBuilder(activeRequest) .setRangeOffset(resumableFile.length()) .build(); activeHttpClient.executeRequest(newRequest, this); deleteFile.set(false); return; } localException.set(false); if (closeOnComplete.get()) { activeHttpClient.close(); } super.onThrowable(t); if (Exception.class.isAssignableFrom(t.getClass())) { exception = Exception.class.cast(t); } else { exception = new Exception(t); } fireTransferFailed(); } catch (Throwable ex) { logger.debug("Unexpected exception", ex); } finally { if (resumableFile != null) { try { resumableFile.close(); } catch (IOException ex) { } } deleteFile(fileLockCompanion); latch.countDown(); removeListeners(); } } private void removeListeners() { removeTransferListener(listener); } public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { if (status() != null && (status().getStatusCode() == 200 || status().getStatusCode() == 206)) { byte[] bytes = content.getBodyPartBytes(); try { // If the content-range header was present, save the bytes at the end of the // file // as we are resuming an existing download. if (seekEndOnFile.get()) { resumableFile.seek(fileLockCompanion.getFile().length()); // No need to seek again. seekEndOnFile.set(false); } resumableFile.write(bytes); } catch (IOException ex) { logger.debug("onBodyPartReceived", ex); exception = ex; localException.set(true); throw ex; } } return super.onBodyPartReceived(content); } @Override public Response onCompleted(Response r) throws Exception { try { deleteFile.set(true); try { resumableFile.close(); } catch (IOException ex) { } final Response response = super.onCompleted(r); handleResponseCode(uri, response.getStatusCode(), response.getStatusText()); if (!ignoreChecksum) { activeHttpClient .getConfig() .executorService() .execute( new Runnable() { public void run() { try { try { Map<String, Object> checksums = ChecksumUtils.calc( fileLockCompanion.getFile(), checksumAlgos.keySet()); if (!verifyChecksum( file, uri, (String) checksums.get("SHA-1"), ".sha1") && !verifyChecksum( file, uri, (String) checksums.get("MD5"), ".md5")) { throw new ChecksumFailureException( "Checksum validation failed" + ", no checksums available from the repository"); } } catch (ChecksumFailureException e) { if (RepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy)) { throw e; } if (listener != null) { listener.transferCorrupted( newEvent( transferResource, e, RequestType.GET, EventType.CORRUPTED)); } } } catch (Exception ex) { exception = ex; } finally { if (exception == null) { try { rename(fileLockCompanion.getFile(), file); releaseLock(fileLockCompanion); } catch (IOException e) { exception = e; } } else { deleteFile(fileLockCompanion); } latch.countDown(); if (closeOnComplete.get()) { activeHttpClient.close(); } } } }); } else { rename(fileLockCompanion.getFile(), file); releaseLock(fileLockCompanion); handleTmpFile.set(false); // asyncHttpClient.close may takes time before all connections get closed. // We unlatch first. latch.countDown(); if (closeOnComplete.get()) { activeHttpClient.close(); } } removeListeners(); return response; } catch (Exception ex) { exception = ex; localException.set(true); throw ex; } finally { try { if (handleTmpFile.get() && fileLockCompanion.getFile() != null) { if (exception != null) { deleteFile(fileLockCompanion); } else if (ignoreChecksum) { rename(fileLockCompanion.getFile(), file); releaseLock(fileLockCompanion); } } } catch (IOException ex) { exception = ex; } } } }; try { if (file == null) { if (!resourceExist(uri)) { throw new ResourceDoesNotExistException( "Could not find " + uri + " in " + repository.getUrl()); } latch.countDown(); } else { if (listener != null) { completionHandler.addTransferListener(listener); listener.transferInitiated( newEvent(transferResource, null, RequestType.GET, EventType.INITIATED)); } activeHttpClient.executeRequest(request, completionHandler); } } catch (Exception ex) { try { if (resumableFile != null) { resumableFile.close(); } } catch (IOException ex2) { } deleteFile(fileLockCompanion); exception = ex; latch.countDown(); } } catch (Throwable t) { deleteFile(fileLockCompanion); try { if (Exception.class.isAssignableFrom(t.getClass())) { exception = Exception.class.cast(t); } else { exception = new Exception(t); } if (listener != null) { listener.transferFailed( newEvent(transferResource, exception, RequestType.GET, EventType.FAILED)); } } finally { latch.countDown(); } } }