/*
* Universal Password Manager
* Copyright (C) 2005-2013 Adrian Smith
*
* This file is part of Universal Password Manager.
*
* Universal Password Manager is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Universal Password Manager is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Universal Password Manager; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com._17od.upm.transport;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import com._17od.upm.util.Preferences;
public class HTTPTransport extends Transport {
private HttpClient client;
public HTTPTransport() {
client = new HttpClient();
Boolean acceptSelfSignedCerts =
new Boolean(Preferences.get(
Preferences.ApplicationOptions.HTTPS_ACCEPT_SELFSIGNED_CERTS));
if (acceptSelfSignedCerts.booleanValue()) {
// Create a Protcol handler which contains a HTTPS socket factory
// capable of accepting self signed and otherwise invalid certificates.
Protocol httpsProtocol = new Protocol("https",
(ProtocolSocketFactory) new EasySSLProtocolSocketFactory(),
443);
Protocol.registerProtocol("https", httpsProtocol);
}
//Get the proxy settings
Boolean proxyEnabled = new Boolean(Preferences.get(Preferences.ApplicationOptions.HTTP_PROXY_ENABLED));
if (proxyEnabled.booleanValue()) {
String proxyHost = Preferences.get(Preferences.ApplicationOptions.HTTP_PROXY_HOST);
String proxyPortStr = Preferences.get(Preferences.ApplicationOptions.HTTP_PROXY_PORT);
String proxyUserName = Preferences.get(Preferences.ApplicationOptions.HTTP_PROXY_USERNAME);
String proxyPassword = Preferences.get(Preferences.ApplicationOptions.HTTP_PROXY_PASSWORD);
String decodedPassword = new String(Base64.decodeBase64(proxyPassword.getBytes()));
if (isNotEmpty(proxyHost)) {
int proxyPort = 0;
if (isNotEmpty(proxyPortStr)) {
proxyPort = Integer.parseInt(proxyPortStr);
client.getHostConfiguration().setProxy(proxyHost, proxyPort);
if (isNotEmpty(proxyUserName) && isNotEmpty(proxyPassword)) {
client.getState().setProxyCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(proxyUserName, decodedPassword));
}
}
}
}
}
public void put(String targetLocation, File file) throws TransportException {
put(targetLocation, file, null, null);
}
public void put(String targetLocation, File file, String username, String password) throws TransportException {
targetLocation = addTrailingSlash(targetLocation) + "upload.php";
PostMethod post = new PostMethod(targetLocation);
//This part is wrapped in a try/finally so that we can ensure
//the connection to the HTTP server is always closed cleanly
try {
Part[] parts = {
new FilePart("userfile", file)
};
post.setRequestEntity(
new MultipartRequestEntity(parts, post.getParams())
);
//Set the HTTP authentication details
if (username != null) {
Credentials creds = new UsernamePasswordCredentials(new String(username), new String(password));
URL url = new URL(targetLocation);
AuthScope authScope = new AuthScope(url.getHost(), url.getPort());
client.getState().setCredentials(authScope, creds);
client.getParams().setAuthenticationPreemptive(true);
}
// This line makes the HTTP call
int status = client.executeMethod(post);
// I've noticed on Windows (at least) that PHP seems to fail when moving files on the first attempt
// The second attempt works so lets just do that
if (status == HttpStatus.SC_OK && post.getResponseBodyAsString().equals("FILE_WASNT_MOVED")) {
status = client.executeMethod(post);
}
if (status != HttpStatus.SC_OK) {
throw new TransportException("There's been some kind of problem uploading a file to the HTTP server.\n\nThe HTTP error message is [" + HttpStatus.getStatusText(status) + "]");
}
if (!post.getResponseBodyAsString().equals("OK") ) {
throw new TransportException("There's been some kind of problem uploading a file to the HTTP server.\n\nThe error message is [" + post.getResponseBodyAsString() + "]");
}
} catch (FileNotFoundException e) {
throw new TransportException(e);
} catch (MalformedURLException e) {
throw new TransportException(e);
} catch (HttpException e) {
throw new TransportException(e);
} catch (IOException e) {
throw new TransportException(e);
} finally {
post.releaseConnection();
}
}
public byte[] get(String url, String fileName) throws TransportException {
return get(url, fileName, null, null);
}
public byte[] get(String url, String fileName, String username, String password) throws TransportException {
url = addTrailingSlash(url);
return get(url + fileName, username, password);
}
public byte[] get(String url, String username, String password) throws TransportException {
byte[] retVal = null;
GetMethod method = new GetMethod(url);
//This part is wrapped in a try/finally so that we can ensure
//the connection to the HTTP server is always closed cleanly
try {
//Set the authentication details
if (username != null) {
Credentials creds = new UsernamePasswordCredentials(new String(username), new String(password));
URL urlObj = new URL(url);
AuthScope authScope = new AuthScope(urlObj.getHost(), urlObj.getPort());
client.getState().setCredentials(authScope, creds);
client.getParams().setAuthenticationPreemptive(true);
}
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
throw new TransportException("There's been some kind of problem getting the URL [" + url + "].\n\nThe HTTP error message is [" + HttpStatus.getStatusText(statusCode) + "]");
}
retVal = method.getResponseBody();
} catch (MalformedURLException e) {
throw new TransportException(e);
} catch (HttpException e) {
throw new TransportException(e);
} catch (IOException e) {
throw new TransportException(e);
} finally {
method.releaseConnection();
}
return retVal;
}
public File getRemoteFile(String remoteLocation, String fileName) throws TransportException {
return getRemoteFile(remoteLocation, fileName, null, null);
}
public File getRemoteFile(String remoteLocation) throws TransportException {
return getRemoteFile(remoteLocation, null, null);
}
public File getRemoteFile(String remoteLocation, String fileName, String httpUsername, String httpPassword) throws TransportException {
remoteLocation = addTrailingSlash(remoteLocation);
return getRemoteFile(remoteLocation + fileName, httpUsername, httpPassword);
}
public File getRemoteFile(String remoteLocation, String httpUsername, String httpPassword) throws TransportException {
try {
byte[] remoteFile = get(remoteLocation, httpUsername, httpPassword);
File downloadedFile = File.createTempFile("upm", null);
FileOutputStream fos = new FileOutputStream(downloadedFile);
fos.write(remoteFile);
fos.close();
return downloadedFile;
} catch (IOException e) {
throw new TransportException(e);
}
}
public void delete(String targetLocation, String name, String username, String password) throws TransportException {
targetLocation = addTrailingSlash(targetLocation) + "deletefile.php";
PostMethod post = new PostMethod(targetLocation);
post.addParameter("fileToDelete", name);
//This part is wrapped in a try/finally so that we can ensure
//the connection to the HTTP server is always closed cleanly
try {
//Set the authentication details
if (username != null) {
Credentials creds = new UsernamePasswordCredentials(new String(username), new String(password));
URL url = new URL(targetLocation);
AuthScope authScope = new AuthScope(url.getHost(), url.getPort());
client.getState().setCredentials(authScope, creds);
client.getParams().setAuthenticationPreemptive(true);
}
int status = client.executeMethod(post);
if (status != HttpStatus.SC_OK) {
throw new TransportException("There's been some kind of problem deleting a file on the HTTP server.\n\nThe HTTP error message is [" + HttpStatus.getStatusText(status) + "]");
}
if (!post.getResponseBodyAsString().equals("OK") ) {
throw new TransportException("There's been some kind of problem deleting a file to the HTTP server.\n\nThe error message is [" + post.getResponseBodyAsString() + "]");
}
} catch (MalformedURLException e) {
throw new TransportException(e);
} catch (HttpException e) {
throw new TransportException(e);
} catch (IOException e) {
throw new TransportException(e);
} finally {
post.releaseConnection();
}
}
public void delete(String targetLocation, String name) throws TransportException {
delete(targetLocation, name, null, null);
}
private String addTrailingSlash(String url) {
if (url.charAt(url.length() - 1) != '/') {
url = url + '/';
}
return url;
}
private boolean isNotEmpty(String stringToCheck) {
boolean retVal = false;
if (stringToCheck != null && !stringToCheck.trim().equals("")) {
retVal = true;
}
return retVal;
}
}