/******************************************************************************* * Copyright (c) 2011, 2016 Eurotech and/or its affiliates * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.deployment.download.impl; import java.io.IOException; import java.net.Authenticator; import java.net.HttpURLConnection; import java.net.PasswordAuthentication; import java.net.URL; import java.net.URLConnection; import java.security.GeneralSecurityException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.net.ssl.HttpsURLConnection; import org.apache.commons.io.IOUtils; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.deployment.CloudDeploymentHandlerV2.DOWNLOAD_STATUS; import org.eclipse.kura.core.deployment.download.DownloadCountingOutputStream; import org.eclipse.kura.core.deployment.download.DownloadOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpDownloadCountingOutputStream extends GenericDownloadCountingOutputStream implements DownloadCountingOutputStream { private static final Logger s_logger = LoggerFactory.getLogger(HttpDownloadCountingOutputStream.class); private ExecutorService executor; private Future<Void> future; public HttpDownloadCountingOutputStream(DownloadOptions downloadOptions) { super(downloadOptions); setBufferSize(this.options.getBlockSize()); setResolution(this.options.getNotifyBlockSize()); setBlockDelay(this.options.getBlockDelay()); setConnectTimeout(this.options.getTimeout()); } @Override public void cancelDownload() throws Exception { if (this.executor != null && this.future != null) { this.future.cancel(true); this.executor.shutdownNow(); postProgressEvent(this.options.getClientId(), getByteCount(), this.totalBytes, DOWNLOAD_STATUS.CANCELLED, "Download cancelled"); } } @Override public void startWork() throws KuraException { this.executor = Executors.newSingleThreadExecutor(); this.future = this.executor.submit(new Callable<Void>() { @Override public Void call() throws Exception { URL localUrl = null; boolean shouldAuthenticate = false; try { shouldAuthenticate = HttpDownloadCountingOutputStream.this.options.getUsername() != null && HttpDownloadCountingOutputStream.this.options.getPassword() != null && !(HttpDownloadCountingOutputStream.this.options.getUsername().trim().isEmpty() && !HttpDownloadCountingOutputStream.this.options.getPassword().trim().isEmpty()); if (shouldAuthenticate) { Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication( HttpDownloadCountingOutputStream.this.options.getUsername(), HttpDownloadCountingOutputStream.this.options.getPassword().toCharArray()); } }); } localUrl = new URL(HttpDownloadCountingOutputStream.this.m_downloadURL); URLConnection urlConnection = localUrl.openConnection(); int connectTimeout = getConnectTimeout(); int readTimeout = getPropReadTimeout(); urlConnection.setConnectTimeout(connectTimeout); urlConnection.setReadTimeout(readTimeout); testConnectionProtocol(urlConnection); HttpDownloadCountingOutputStream.this.is = localUrl.openStream(); String s = urlConnection.getHeaderField("Content-Length"); s_logger.info("Content-lenght: " + s); setTotalBytes(s != null ? Integer.parseInt(s) : -1); postProgressEvent(HttpDownloadCountingOutputStream.this.options.getClientId(), 0, HttpDownloadCountingOutputStream.this.totalBytes, DOWNLOAD_STATUS.IN_PROGRESS, null); int bufferSize = getBufferSize(); if (bufferSize == 0 && getTotalBytes() > 0) { int newSize = Math.round(HttpDownloadCountingOutputStream.this.totalBytes / 100 * 1); bufferSize = newSize; setBufferSize(newSize); } else if (bufferSize == 0) { int newSize = 1024 * 4; bufferSize = newSize; setBufferSize(newSize); } long numBytes = IOUtils.copyLarge(HttpDownloadCountingOutputStream.this.is, HttpDownloadCountingOutputStream.this, new byte[bufferSize]); postProgressEvent(HttpDownloadCountingOutputStream.this.options.getClientId(), numBytes, HttpDownloadCountingOutputStream.this.totalBytes, DOWNLOAD_STATUS.COMPLETED, null); } catch (IOException e) { postProgressEvent(HttpDownloadCountingOutputStream.this.options.getClientId(), getByteCount(), HttpDownloadCountingOutputStream.this.totalBytes, DOWNLOAD_STATUS.FAILED, e.getMessage()); throw new KuraConnectException(e); } finally { if (HttpDownloadCountingOutputStream.this.is != null) { try { HttpDownloadCountingOutputStream.this.is.close(); } catch (IOException e) { } } try { close(); } catch (IOException e) { } localUrl = null; if (shouldAuthenticate) { Authenticator.setDefault(null); } } return null; } }); try { this.future.get(); } catch (ExecutionException ex) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, ex); } catch (InterruptedException ex) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, ex); } } private void testConnectionProtocol(URLConnection urlConnection) throws IOException, KuraConnectException { try { if (urlConnection instanceof HttpsURLConnection) { ((HttpsURLConnection) urlConnection) .setSSLSocketFactory(this.m_sslManagerService.getSSLSocketFactory()); } else if (!(urlConnection instanceof HttpURLConnection)) { postProgressEvent(this.options.getClientId(), getByteCount(), this.totalBytes, DOWNLOAD_STATUS.FAILED, "The request URL is not supported"); throw new KuraConnectException("Unsupported protocol!"); } } catch (GeneralSecurityException e) { postProgressEvent(this.options.getClientId(), getByteCount(), this.totalBytes, DOWNLOAD_STATUS.FAILED, e.getMessage()); throw new KuraConnectException(e, "Unsupported protocol!"); } } }