package net.flibusta.download.impl;
import net.flibusta.download.DownloadException;
import net.flibusta.download.DownloadService;
import net.flibusta.util.TempFileUtil;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import java.io.*;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class SyncHttpDownloadService implements DownloadService {
Logger logger = Logger.getLogger(SyncHttpDownloadService.class);
private HttpClient httpClient = null;
@Override
public File fetch(URL url) throws Exception {
HttpClient httpClient = getHttpClient();
String uri = url.toString();
GetMethod method = new GetMethod(uri);
method.getParams().setParameter(HttpMethodParams.USER_AGENT, "Mobipocket/ePub Converter");
// method.getParams().setParameter(HttpMethodParams.USER_AGENT, "Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5");
int retryCount = 10;
int code;
String fileName;
File file;
try {
try {
do {
logger.debug("Start download " + url + " try=" + (10 - retryCount));
code = httpClient.executeMethod(method);
if (code == 503) {
Thread.sleep(500);
}
} while (code == 503 && retryCount-- > 0);
} catch (IOException e) {
logger.error("Download from " + uri + " failed with exception " + e.getMessage(), e);
method.releaseConnection();
throw new DownloadException("Download from " + uri + " failed with exception " + e.getMessage(), e);
}
if (code != 200) {
method.releaseConnection();
throw new DownloadException("File download failed with code " + code + " from url " + uri);
}
InputStream sourceStream = method.getResponseBodyAsStream();
fileName = method.getPath();
Header responseHeader = method.getResponseHeader("Content-Disposition");
if (responseHeader != null) {
String value = responseHeader.getValue();
if (value.contains("attachment; filename=\"")) {
fileName = value.substring("attachment; filename=\"".length(), value.length() - 1);
}
}
file = createTempFile(fileName);
OutputStream targetStream = new FileOutputStream(file);
try {
IOUtils.copy(sourceStream, targetStream);
} catch (Exception e) {
IOUtils.closeQuietly(targetStream);
FileUtils.deleteQuietly(file);
throw e;
} finally {
IOUtils.closeQuietly(sourceStream);
IOUtils.closeQuietly(targetStream);
method.releaseConnection();
}
} finally {
method.releaseConnection();
httpClient.getHttpConnectionManager().closeIdleConnections(0);
}
Header contentType = method.getResponseHeader("Content-Type");
if ((contentType != null && "application/zip".equals(contentType.getValue())) || fileName.endsWith(".zip")) {
file = unzip(file);
}
logger.debug("Downloaded " + file.getName());
return file;
}
private File createTempFile(String path) throws IOException {
String name = FilenameUtils.getName(path);
if (name.length() == 0) {
return File.createTempFile("tmp", null);
}
File systemTempDir = new File(System.getProperty("java.io.tmpdir"));
return new File(systemTempDir, name);
}
private HttpClient getHttpClient() {
HttpConnectionManager httpConnectionManager = new SimpleHttpConnectionManager(false);
HttpConnectionManagerParams params = httpConnectionManager.getParams();
params.setDefaultMaxConnectionsPerHost(20);
params.setMaxTotalConnections(30);
params.setLinger(10);
HostConfiguration hostConfiguration;
hostConfiguration = new HostConfiguration();
hostConfiguration.setHost("static.flibusta.net");
params.setMaxConnectionsPerHost(hostConfiguration, 6);
httpClient = new HttpClient(httpConnectionManager);
return httpClient;
}
// private synchronized HttpClient getHttpClient() {
// if (httpClient == null) {
// HttpConnectionManager httpConnectionManager = new SimpleHttpConnectionManager(false);
// HttpConnectionManagerParams params = httpConnectionManager.getParams();
// params.setDefaultMaxConnectionsPerHost(20);
// params.setMaxTotalConnections(30);
// params.setLinger(10);
//
// HostConfiguration hostConfiguration;
// hostConfiguration = new HostConfiguration();
// hostConfiguration.setHost("static.flibusta.net");
// params.setMaxConnectionsPerHost(hostConfiguration, 6);
// httpClient = new HttpClient(httpConnectionManager);
//
// }
// return httpClient;
// }
public void shutdown() {
HttpConnectionManager connectionManager = getHttpClient().getHttpConnectionManager();
if (connectionManager instanceof MultiThreadedHttpConnectionManager) {
MultiThreadedHttpConnectionManager manager = (MultiThreadedHttpConnectionManager) connectionManager;
manager.shutdown();
}
}
private File unzip(File file) throws Exception {
File tempDir = TempFileUtil.createTempDir();
File tempFile = null;
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(file));
try {
ZipEntry zipEntry;
int archiveFileCount = 0;
while ((zipEntry = inputStream.getNextEntry()) != null) {
if (zipEntry.getName().endsWith(".fbd")) {
continue;
}
tempFile = new File(tempDir, zipEntry.getName());
OutputStream outputStream = new FileOutputStream(tempFile);
try {
IOUtils.copy(inputStream, outputStream);
} finally {
IOUtils.closeQuietly(outputStream);
}
if (++archiveFileCount > 1) {
throw new Exception("Multifile archives not supported");
}
}
} finally {
IOUtils.closeQuietly(inputStream);
file.delete();
}
if (tempFile == null) {
FileUtils.deleteDirectory(tempDir);
return null;
}
// move unpacked file to upper level and remove temporary directory
File systemTempDir = new File(System.getProperty("java.io.tmpdir"));
String tempFileName = tempFile.getName();
boolean isFileMoved = false;
int tryCount = 20;
File targetFile;
do {
targetFile = new File(systemTempDir, tempFileName);
try {
FileUtils.moveFile(tempFile, targetFile);
isFileMoved = true;
} catch (IOException e) {
tempFileName = tempFileName.substring(0, 1) + tempFileName;
}
} while (!isFileMoved && tryCount-- > 0);
FileUtils.deleteDirectory(tempDir);
if (!isFileMoved) {
throw new IOException("Can't move file " + tempFile.getName() + " to " + systemTempDir.getName());
}
return targetFile;
}
}