added download() to the filetransfer

This commit is contained in:
Alexander Keller 2011-11-26 18:16:44 +01:00
parent 853a734f82
commit 8904c67fb5
2 changed files with 313 additions and 257 deletions

View File

@ -83,6 +83,17 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]); PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]);
}; };
/**
* Downloads a file form a given URL and saves it to the specified directory.
* @param sourceUrl {String} URL of the server to receive the file
* @param targetFile {String} Full path of the file on the device
* @param successCallback (Function} Callback to be invoked when upload has completed
* @param errorCallback {Function} Callback to be invoked upon error
*/
FileTransfer.prototype.download = function(sourceUrl, targetFile, successCallback, errorCallback) {
PhoneGap.exec(successCallback, errorCallback, 'FileTransfer', 'download', [targetFile, sourceUrl]);
};
/** /**
* Options to customize the HTTP request used to upload files. * Options to customize the HTTP request used to upload files.
* @constructor * @constructor

View File

@ -20,8 +20,10 @@ package com.phonegap;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@ -52,98 +54,100 @@ import com.phonegap.api.PluginResult;
public class FileTransfer extends Plugin { public class FileTransfer extends Plugin {
private static final String LOG_TAG = "FileUploader"; private static final String LOG_TAG = "FileUploader";
private static final String LINE_START = "--"; private static final String LINE_START = "--";
private static final String LINE_END = "\r\n"; private static final String LINE_END = "\r\n";
private static final String BOUNDRY = "*****"; private static final String BOUNDRY = "*****";
public static int FILE_NOT_FOUND_ERR = 1; public static int FILE_NOT_FOUND_ERR = 1;
public static int INVALID_URL_ERR = 2; public static int INVALID_URL_ERR = 2;
public static int CONNECTION_ERR = 3; public static int CONNECTION_ERR = 3;
private SSLSocketFactory defaultSSLSocketFactory = null; private SSLSocketFactory defaultSSLSocketFactory = null;
private HostnameVerifier defaultHostnameVerifier = null; private HostnameVerifier defaultHostnameVerifier = null;
/* (non-Javadoc) /* (non-Javadoc)
* @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String) * @see com.phonegap.api.Plugin#execute(java.lang.String, org.json.JSONArray, java.lang.String)
*/ */
@Override @Override
public PluginResult execute(String action, JSONArray args, String callbackId) { public PluginResult execute(String action, JSONArray args, String callbackId) {
String file = null; String file = null;
String server = null; String server = null;
try { try {
file = args.getString(0); file = args.getString(0);
server = args.getString(1); server = args.getString(1);
} }
catch (JSONException e) { catch (JSONException e) {
Log.d(LOG_TAG, "Missing filename or server name"); Log.d(LOG_TAG, "Missing filename or server name");
return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing filename or server name"); return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Missing filename or server name");
} }
// Setup the options
String fileKey = null;
String fileName = null;
String mimeType = null;
fileKey = getArgument(args, 2, "file");
fileName = getArgument(args, 3, "image.jpg");
mimeType = getArgument(args, 4, "image/jpeg");
try { try {
JSONObject params = args.optJSONObject(5); if (action.equals("upload")) {
boolean trustEveryone = args.optBoolean(6); // Setup the options
boolean chunkedMode = args.getBoolean(7); String fileKey = null;
String fileName = null;
String mimeType = null;
if (action.equals("upload")) { fileKey = getArgument(args, 2, "file");
FileUploadResult r = upload(file, server, fileKey, fileName, mimeType, params, trustEveryone, chunkedMode); fileName = getArgument(args, 3, "image.jpg");
Log.d(LOG_TAG, "****** About to return a result from upload"); mimeType = getArgument(args, 4, "image/jpeg");
return new PluginResult(PluginResult.Status.OK, r.toJSONObject()); JSONObject params = args.optJSONObject(5);
} else { boolean trustEveryone = args.optBoolean(6);
return new PluginResult(PluginResult.Status.INVALID_ACTION); boolean chunkedMode = args.getBoolean(7);
} FileUploadResult r = upload(file, server, fileKey, fileName, mimeType, params, trustEveryone, chunkedMode);
} catch (FileNotFoundException e) { Log.d(LOG_TAG, "****** About to return a result from upload");
Log.e(LOG_TAG, e.getMessage(), e); return new PluginResult(PluginResult.Status.OK, r.toJSONObject());
JSONObject error = createFileUploadError(FILE_NOT_FOUND_ERR); } else if (action.equals("download")) {
String r = download(file, server);
Log.d(LOG_TAG, "****** About to return a result from download");
return new PluginResult(PluginResult.Status.OK, r);
} else {
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, e.getMessage(), e);
JSONObject error = createFileUploadError(FILE_NOT_FOUND_ERR);
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error); return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
JSONObject error = createFileUploadError(INVALID_URL_ERR); JSONObject error = createFileUploadError(INVALID_URL_ERR);
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error); return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
} catch (SSLException e) { } catch (SSLException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
Log.d(LOG_TAG, "Got my ssl exception!!!"); Log.d(LOG_TAG, "Got my ssl exception!!!");
JSONObject error = createFileUploadError(CONNECTION_ERR); JSONObject error = createFileUploadError(CONNECTION_ERR);
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error); return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
} catch (IOException e) { } catch (IOException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
JSONObject error = createFileUploadError(CONNECTION_ERR); JSONObject error = createFileUploadError(CONNECTION_ERR);
return new PluginResult(PluginResult.Status.IO_EXCEPTION, error); return new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
return new PluginResult(PluginResult.Status.JSON_EXCEPTION); return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
// always verify the host - don't check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
} }
}; }
/** // always verify the host - don't check for certificate
* This function will install a trust manager that will blindly trust all SSL final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
* certificates. The reason this code is being added is to enable developers public boolean verify(String hostname, SSLSession session) {
* to do development using self signed SSL certificates on their web server. return true;
* }
* The standard HttpsURLConnection class will throw an exception on self };
* signed certificates if this code is not run.
*/ /**
private void trustAllHosts() { * This function will install a trust manager that will blindly trust all SSL
* certificates. The reason this code is being added is to enable developers
* to do development using self signed SSL certificates on their web server.
*
* The standard HttpsURLConnection class will throw an exception on self
* signed certificates if this code is not run.
*/
private void trustAllHosts() {
// Create a trust manager that does not validate certificate chains // Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() { public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {}; return new java.security.cert.X509Certificate[] {};
} }
public void checkClientTrusted(X509Certificate[] chain, public void checkClientTrusted(X509Certificate[] chain,
@ -157,54 +161,54 @@ public class FileTransfer extends Plugin {
// Install the all-trusting trust manager // Install the all-trusting trust manager
try { try {
// Backup the current SSL socket factory // Backup the current SSL socket factory
defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
// Install our all trusting manager // Install our all trusting manager
SSLContext sc = SSLContext.getInstance("TLS"); SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom()); sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, e.getMessage(), e); Log.e(LOG_TAG, e.getMessage(), e);
} }
} }
/**
* Create an error object based on the passed in errorCode
* @param errorCode the error
* @return JSONObject containing the error
*/
private JSONObject createFileUploadError(int errorCode) {
JSONObject error = null;
try {
error = new JSONObject();
error.put("code", errorCode);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
return error;
}
/**
* Convenience method to read a parameter from the list of JSON args.
* @param args the args passed to the Plugin
* @param position the position to retrieve the arg from
* @param defaultString the default to be used if the arg does not exist
* @return String with the retrieved value
*/
private String getArgument(JSONArray args, int position, String defaultString) {
String arg = defaultString;
if(args.length() >= position) {
arg = args.optString(position);
if (arg == null || "null".equals(arg)) {
arg = defaultString;
}
}
return arg;
}
/** /**
* Uploads the specified file to the server URL provided using an HTTP * Create an error object based on the passed in errorCode
* multipart request. * @param errorCode the error
* @return JSONObject containing the error
*/
private JSONObject createFileUploadError(int errorCode) {
JSONObject error = null;
try {
error = new JSONObject();
error.put("code", errorCode);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
return error;
}
/**
* Convenience method to read a parameter from the list of JSON args.
* @param args the args passed to the Plugin
* @param position the position to retrieve the arg from
* @param defaultString the default to be used if the arg does not exist
* @return String with the retrieved value
*/
private String getArgument(JSONArray args, int position, String defaultString) {
String arg = defaultString;
if(args.length() >= position) {
arg = args.optString(position);
if (arg == null || "null".equals(arg)) {
arg = defaultString;
}
}
return arg;
}
/**
* Uploads the specified file to the server URL provided using an HTTP
* multipart request.
* @param file Full path of the file on the file system * @param file Full path of the file on the file system
* @param server URL of the server to receive the file * @param server URL of the server to receive the file
* @param fileKey Name of file request parameter * @param fileKey Name of file request parameter
@ -213,173 +217,214 @@ public class FileTransfer extends Plugin {
* @param params key:value pairs of user-defined parameters * @param params key:value pairs of user-defined parameters
* @return FileUploadResult containing result of upload request * @return FileUploadResult containing result of upload request
*/ */
public FileUploadResult upload(String file, String server, final String fileKey, final String fileName, public FileUploadResult upload(String file, String server, final String fileKey, final String fileName,
final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException { final String mimeType, JSONObject params, boolean trustEveryone, boolean chunkedMode) throws IOException, SSLException {
// Create return object // Create return object
FileUploadResult result = new FileUploadResult(); FileUploadResult result = new FileUploadResult();
// Get a input stream of the file on the phone
InputStream fileInputStream = getPathFromUri(file);
HttpURLConnection conn = null; // Get a input stream of the file on the phone
DataOutputStream dos = null; InputStream fileInputStream = getPathFromUri(file);
int bytesRead, bytesAvailable, bufferSize; HttpURLConnection conn = null;
long totalBytes; DataOutputStream dos = null;
byte[] buffer;
int maxBufferSize = 8096;
//------------------ CLIENT REQUEST int bytesRead, bytesAvailable, bufferSize;
// open a URL connection to the server long totalBytes;
URL url = new URL(server); byte[] buffer;
int maxBufferSize = 8096;
// Open a HTTP connection to the URL based on protocol
//------------------ CLIENT REQUEST
// open a URL connection to the server
URL url = new URL(server);
// Open a HTTP connection to the URL based on protocol
if (url.getProtocol().toLowerCase().equals("https")) { if (url.getProtocol().toLowerCase().equals("https")) {
// Using standard HTTPS connection. Will not allow self signed certificate // Using standard HTTPS connection. Will not allow self signed certificate
if (!trustEveryone) { if (!trustEveryone) {
conn = (HttpsURLConnection) url.openConnection(); conn = (HttpsURLConnection) url.openConnection();
} }
// Use our HTTPS connection that blindly trusts everyone. // Use our HTTPS connection that blindly trusts everyone.
// This should only be used in debug environments // This should only be used in debug environments
else { else {
// Setup the HTTPS connection class to trust everyone // Setup the HTTPS connection class to trust everyone
trustAllHosts(); trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
// Save the current hostnameVerifier // Save the current hostnameVerifier
defaultHostnameVerifier = https.getHostnameVerifier(); defaultHostnameVerifier = https.getHostnameVerifier();
// Setup the connection not to verify hostnames // Setup the connection not to verify hostnames
https.setHostnameVerifier(DO_NOT_VERIFY); https.setHostnameVerifier(DO_NOT_VERIFY);
conn = https; conn = https;
} }
} }
// Return a standard HTTP connection // Return a standard HTTP connection
else { else {
conn = (HttpURLConnection) url.openConnection(); conn = (HttpURLConnection) url.openConnection();
} }
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+BOUNDRY);
// Set the cookies on the response // Allow Inputs
String cookie = CookieManager.getInstance().getCookie(server); conn.setDoInput(true);
if (cookie != null) {
conn.setRequestProperty("Cookie", cookie);
}
// Should set this up as an option
if (chunkedMode) {
conn.setChunkedStreamingMode(maxBufferSize);
}
dos = new DataOutputStream( conn.getOutputStream() );
// Send any extra parameters // Allow Outputs
try { conn.setDoOutput(true);
for (Iterator iter = params.keys(); iter.hasNext();) {
Object key = iter.next();
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name=\"" + key.toString() + "\";");
dos.writeBytes(LINE_END + LINE_END);
dos.write(params.getString(key.toString()).getBytes());
dos.writeBytes(LINE_END);
}
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"" + fileName +"\"" + LINE_END);
dos.writeBytes("Content-Type: " + mimeType + LINE_END);
dos.writeBytes(LINE_END);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
totalBytes = 0;
while (bytesRead > 0) { // Don't use a cached copy.
totalBytes += bytesRead; conn.setUseCaches(false);
result.setBytesSent(totalBytes);
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data... // Use a post method.
dos.writeBytes(LINE_END); conn.setRequestMethod("POST");
dos.writeBytes(LINE_START + BOUNDRY + LINE_START + LINE_END); conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+BOUNDRY);
// close streams
fileInputStream.close();
dos.flush();
dos.close();
//------------------ read the SERVER RESPONSE // Set the cookies on the response
StringBuffer responseString = new StringBuffer(""); String cookie = CookieManager.getInstance().getCookie(server);
DataInputStream inStream; if (cookie != null) {
try { conn.setRequestProperty("Cookie", cookie);
inStream = new DataInputStream ( conn.getInputStream() ); }
} catch(FileNotFoundException e) {
throw new IOException("Received error from server");
}
String line;
while (( line = inStream.readLine()) != null) {
responseString.append(line);
}
Log.d(LOG_TAG, "got response from server");
Log.d(LOG_TAG, responseString.toString());
// send request and retrieve response // Should set this up as an option
if (chunkedMode) {
conn.setChunkedStreamingMode(maxBufferSize);
}
dos = new DataOutputStream( conn.getOutputStream() );
// Send any extra parameters
try {
for (Iterator iter = params.keys(); iter.hasNext();) {
Object key = iter.next();
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name=\"" + key.toString() + "\";");
dos.writeBytes(LINE_END + LINE_END);
dos.write(params.getString(key.toString()).getBytes());
dos.writeBytes(LINE_END);
}
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
dos.writeBytes(LINE_START + BOUNDRY + LINE_END);
dos.writeBytes("Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"" + fileName +"\"" + LINE_END);
dos.writeBytes("Content-Type: " + mimeType + LINE_END);
dos.writeBytes(LINE_END);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
totalBytes = 0;
while (bytesRead > 0) {
totalBytes += bytesRead;
result.setBytesSent(totalBytes);
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(LINE_END);
dos.writeBytes(LINE_START + BOUNDRY + LINE_START + LINE_END);
// close streams
fileInputStream.close();
dos.flush();
dos.close();
//------------------ read the SERVER RESPONSE
StringBuffer responseString = new StringBuffer("");
DataInputStream inStream;
try {
inStream = new DataInputStream ( conn.getInputStream() );
} catch(FileNotFoundException e) {
throw new IOException("Received error from server");
}
String line;
while (( line = inStream.readLine()) != null) {
responseString.append(line);
}
Log.d(LOG_TAG, "got response from server");
Log.d(LOG_TAG, responseString.toString());
// send request and retrieve response
result.setResponseCode(conn.getResponseCode()); result.setResponseCode(conn.getResponseCode());
result.setResponse(responseString.toString()); result.setResponse(responseString.toString());
inStream.close(); inStream.close();
conn.disconnect(); conn.disconnect();
// Revert back to the proper verifier and socket factories // Revert back to the proper verifier and socket factories
if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) { if (trustEveryone && url.getProtocol().toLowerCase().equals("https")) {
((HttpsURLConnection)conn).setHostnameVerifier(defaultHostnameVerifier); ((HttpsURLConnection)conn).setHostnameVerifier(defaultHostnameVerifier);
HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory); HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory);
} }
return result;
}
/** return result;
}
/**
* Downloads a file form a given URL and saves it to the specified directory.
*
* @param server URL of the server to receive the file
* @param file Full path of the file on the file system
* @return String containing the path to the downloaded file
*/
public String download(String filePath, String sourceUrl) throws IOException {
try {
File file = new File(filePath);
file.getParentFile().mkdirs();
URL url = new URL(sourceUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.connect();
Log.d(LOG_TAG, "Download file:" + url);
InputStream inputStream = connection.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
FileOutputStream outputStream = new FileOutputStream(file);
while ( (len1 = inputStream.read(buffer)) > 0 ) {
outputStream.write(buffer,0, len1);
}
outputStream.close();
Log.d(LOG_TAG, "Saved file: " + filePath);
} catch (IOException e) {
Log.d(LOG_TAG, e.getMessage(), e);
throw new IOException("Error while downloading");
}
return filePath;
}
/**
* Get an input stream based on file path or content:// uri * Get an input stream based on file path or content:// uri
* *
* @param path * @param path
* @return an input stream * @return an input stream
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
private InputStream getPathFromUri(String path) throws FileNotFoundException { private InputStream getPathFromUri(String path) throws FileNotFoundException {
if (path.startsWith("content:")) { if (path.startsWith("content:")) {
Uri uri = Uri.parse(path); Uri uri = Uri.parse(path);
return ctx.getContentResolver().openInputStream(uri); return ctx.getContentResolver().openInputStream(uri);
} }
else if (path.startsWith("file://")) { else if (path.startsWith("file://")) {
return new FileInputStream(path.substring(7)); return new FileInputStream(path.substring(7));
} }
else { else {
return new FileInputStream(path); return new FileInputStream(path);
} }
} }
} }