/*
* Geopaparazzi - Digital field mapping on Android based devices
* Copyright (C) 2016 HydroloGIS (www.hydrologis.com)
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.geopaparazzi.library.network;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.http.AndroidHttpClient;
import android.util.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import eu.geopaparazzi.library.R;
import eu.geopaparazzi.library.database.GPLog;
import eu.geopaparazzi.library.util.GPDialogs;
import eu.geopaparazzi.library.util.TimeUtilities;
/**
* Network utils methods.
*
* @author Andrea Antonello (www.hydrologis.com)
*/
@SuppressWarnings("nls")
public class NetworkUtilities {
private static final String TAG = "NETWORKUTILITIES";
/**
*
*/
public static final long maxBufferSize = 4096;
public static final String SLASH = "/";
/**
* Read url to string.
*
* @param urlString the url.
* @return the fetched text.
* @throws Exception if something goes wrong.
*/
public static String readUrl(String urlString) throws Exception {
URL url = new URL(urlString);
InputStream inputStream = url.openStream();
BufferedReader bi = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = bi.readLine()) != null) {
sb.append(line).append("\n");
}
inputStream.close();
return sb.toString().trim();
}
private static HttpURLConnection makeNewConnection(String fileUrl) throws Exception {
URL url = new URL(normalizeUrl(fileUrl));
return (HttpURLConnection) url.openConnection();
}
private static String normalizeUrl(String url) {
return normalizeUrl(url, false);
}
private static String normalizeUrl(String url, boolean addSlash) {
if ( (!url.startsWith("http://")) && (!url.startsWith("https://"))) {
url = "http://" + url;
}
if (addSlash && !url.endsWith(SLASH)) {
url = url + SLASH;
}
return url;
}
/**
* Sends an HTTP GET request to a url
*
* @param urlStr - The URL of the server. (Example: " http://www.yahoo.com/search")
* @param file the output file. If it is a folder, it tries to get the file name from the header.
* @param requestParameters - all the request parameters (Example: "param1=val1¶m2=val2").
* Note: This method will add the question mark (?) to the request -
* DO NOT add it yourself
* @param user user.
* @param password password.
* @return the file written.
* @throws Exception if something goes wrong.
*/
public static File sendGetRequest4File(String urlStr, File file, String requestParameters, String user, String password)
throws Exception {
if (requestParameters != null && requestParameters.length() > 0) {
urlStr += "?" + requestParameters;
}
HttpURLConnection conn = makeNewConnection(urlStr);
conn.setRequestMethod("GET");
// conn.setDoOutput(true);
conn.setDoInput(true);
// conn.setChunkedStreamingMode(0);
conn.setUseCaches(false);
if (user != null && password != null && user.trim().length() > 0 && password.trim().length() > 0) {
conn.setRequestProperty("Authorization", getB64Auth(user, password));
}
conn.connect();
if (file.isDirectory()) {
// try to get the header
String headerField = conn.getHeaderField("Content-Disposition");
String fileName = null;
if (headerField != null) {
String[] split = headerField.split(";");
for (String string : split) {
String pattern = "filename=";
if (string.toLowerCase().startsWith(pattern)) {
fileName = string.replaceFirst(pattern, "");
break;
}
}
}
if (fileName == null) {
// give a name
fileName = "FILE_" + TimeUtilities.INSTANCE.TIMESTAMPFORMATTER_LOCAL.format(new Date());
}
file = new File(file, fileName);
}
InputStream in = null;
FileOutputStream out = null;
try {
in = conn.getInputStream();
out = new FileOutputStream(file);
byte[] buffer = new byte[(int) maxBufferSize];
int bytesRead = in.read(buffer, 0, (int) maxBufferSize);
while (bytesRead > 0) {
out.write(buffer, 0, bytesRead);
bytesRead = in.read(buffer, 0, (int) maxBufferSize);
}
out.flush();
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
if (conn != null)
conn.disconnect();
}
return file;
}
/**
* Sends a string via POST to a given url.
*
* @param context the context to use.
* @param urlStr the url to which to send to.
* @param string the string to send as post body.
* @param user the user or <code>null</code>.
* @param password the password or <code>null</code>.
* @param readResponse if <code>true</code>, the response from the server is read and parsed as return message.
* @return the response.
* @throws Exception if something goes wrong.
*/
public static String sendPost(Context context, String urlStr, String string, String user, String password,
boolean readResponse) throws Exception {
BufferedOutputStream wr = null;
HttpURLConnection conn = null;
try {
conn = makeNewConnection(urlStr);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
// conn.setChunkedStreamingMode(0);
conn.setUseCaches(false);
if (user != null && password != null && user.trim().length() > 0 && password.trim().length() > 0) {
conn.setRequestProperty("Authorization", getB64Auth(user, password));
}
conn.connect();
// Make server believe we are form data...
wr = new BufferedOutputStream(conn.getOutputStream());
byte[] bytes = string.getBytes();
wr.write(bytes);
wr.flush();
int responseCode = conn.getResponseCode();
if (readResponse) {
StringBuilder returnMessageBuilder = new StringBuilder();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
while (true) {
String line = br.readLine();
if (line == null)
break;
returnMessageBuilder.append(line + "\n");
}
br.close();
}
return returnMessageBuilder.toString();
} else {
return getMessageForCode(context, responseCode, context.getResources()
.getString(R.string.post_completed_properly));
}
} catch (Exception e) {
throw e;
} finally {
if (conn != null)
conn.disconnect();
}
}
/**
* Sends a string via POST to a given url expecting a file in return.
*
* @param context the context to use.
* @param urlStr the url to which to send to.
* @param string the string to send as post body.
* @param user the user or <code>null</code>.
* @param password the password or <code>null</code>.
* @param outputFile the file to save to.
* @throws Exception if something goes wrong.
*/
public static void sendPostForFile(Context context, String urlStr, String string, String user, String password,
File outputFile) throws Exception {
BufferedOutputStream wr = null;
HttpURLConnection conn = null;
try {
if (!urlStr.endsWith(SLASH)) {
urlStr = urlStr + SLASH;
}
conn = makeNewConnection(urlStr);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
// conn.setChunkedStreamingMode(0);
conn.setUseCaches(false);
if (user != null && password != null && user.trim().length() > 0 && password.trim().length() > 0) {
conn.setRequestProperty("Authorization", getB64Auth(user, password));
}
conn.connect();
// Make server believe we are form data...
wr = new BufferedOutputStream(conn.getOutputStream());
byte[] bytes = string.getBytes();
wr.write(bytes);
wr.flush();
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = null;
FileOutputStream out = null;
long bytesCount = 0;
try {
in = conn.getInputStream();
out = new FileOutputStream(outputFile);
byte[] buffer = new byte[(int) maxBufferSize];
int bytesRead = in.read(buffer, 0, (int) maxBufferSize);
while (bytesRead > 0) {
out.write(buffer, 0, bytesRead);
bytesRead = in.read(buffer, 0, (int) maxBufferSize);
bytesCount += bytesRead;
}
out.flush();
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
if (bytesCount == 0) {
throw new RuntimeException("Error downloading the data. Buffer was empty.");
}
} else {
throw new RuntimeException("Error downloading the data. Got error code: " + responseCode);
}
} catch (Exception e) {
throw e;
} finally {
if (conn != null)
conn.disconnect();
}
}
/**
* Get a default message for an HTTP code.
*
* @param context the context to use.
* @param responseCode the http code.
* @param defaultOkMessage an optional message for the ok code.
* @return the message.
*/
public static String getMessageForCode(Context context, int responseCode, String defaultOkMessage) {
Resources resources = context.getResources();
switch (responseCode) {
case HttpURLConnection.HTTP_OK:
if (defaultOkMessage != null) {
return defaultOkMessage;
} else {
return resources.getString(R.string.http_ok_msg);
}
case HttpURLConnection.HTTP_FORBIDDEN:
return resources.getString(R.string.http_forbidden_msg);
case HttpURLConnection.HTTP_UNAUTHORIZED:
return resources.getString(R.string.http_forbidden_msg);
case HttpURLConnection.HTTP_NOT_FOUND:
return resources.getString(R.string.http_not_found_msg);
default:
return resources.getString(R.string.http_not_implemented_code_msg) + " " + responseCode;
}
}
/**
* Sends a {@link MultipartEntity} post with text and image files.
*
* @param url the url to which to POST to.
* @param user the user or <code>null</code>.
* @param pwd the password or <code>null</code>.
* @param stringsMap the {@link HashMap} containing the key and string pairs to send.
* @param filesMap the {@link HashMap} containing the key and image file paths
* (jpg, png supported) pairs to send.
* @throws Exception if something goes wrong.
*/
public static void sentMultiPartPost(String url, String user, String pwd, HashMap<String, String> stringsMap,
HashMap<String, File> filesMap) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost(url);
if (user != null && pwd != null && user.trim().length() > 0 && pwd.trim().length() > 0) {
String ret = getB64Auth(user, pwd);
httppost.setHeader("Authorization", ret);
}
MultipartEntity mpEntity = new MultipartEntity();
Set<Entry<String, String>> stringsEntrySet = stringsMap.entrySet();
for (Entry<String, String> stringEntry : stringsEntrySet) {
ContentBody cbProperties = new StringBody(stringEntry.getValue());
mpEntity.addPart(stringEntry.getKey(), cbProperties);
}
Set<Entry<String, File>> filesEntrySet = filesMap.entrySet();
for (Entry<String, File> filesEntry : filesEntrySet) {
String propName = filesEntry.getKey();
File file = filesEntry.getValue();
if (file.exists()) {
String ext = file.getName().toLowerCase().endsWith("jpg") ? "jpeg" : "png";
ContentBody cbFile = new FileBody(file, "image/" + ext);
mpEntity.addPart(propName, cbFile);
}
}
httppost.setEntity(mpEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
public static String getB64Auth(String login, String pass) {
String source = login + ":" + pass;
String ret = "Basic " + Base64.encodeToString(source.getBytes(), Base64.URL_SAFE | Base64.NO_WRAP);
return ret;
}
/**
* Checks is the network is available.
*
* @param context the {@link Context}.
* @return true if the network is available.
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
return false;
} else {
NetworkInfo networkInfo = connectivity.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
}
/**
* Checks is the mobile network is connected.
*
* @param context the {@link Context}.
* @return true if the mobile network is connected.
*/
public static boolean isConnectionMobile(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
return false;
}
NetworkInfo networkInfo = connectivity.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); // for wifi ConnectivityManager.TYPE_WIFI
boolean isMobileConn = networkInfo.isConnected();
return isMobileConn;
}
/**
* Send a GET request.
*
* @param urlStr the url.
* @param requestParameters request parameters or <code>null</code>.
* @param user user or <code>null</code>.
* @param password password or <code>null</code>.
* @return the fetched text.
* @throws Exception if something goes wrong.
*/
public static String sendGetRequest(String urlStr, String requestParameters, String user, String password) throws Exception {
urlStr = normalizeUrl(urlStr);
if (requestParameters != null && requestParameters.length() > 0) {
urlStr += "?" + requestParameters;
}
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urlStr);
if (user != null && password != null && user.trim().length() > 0 && password.trim().length() > 0) {
httpGet.addHeader("Authorization", getB64Auth(user, password));
}
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} else {
String message = "Failed the http GET request.";
IOException ioException = new IOException(message);
GPLog.error(TAG, message, ioException);
throw ioException;
}
return builder.toString();
}
/**
* Send a file via HTTP POST with basic authentication.
*
* @param context the context to use.
* @param urlStr the server url to POST to.
* @param file the file to send.
* @param user the user or <code>null</code>.
* @param password the password or <code>null</code>.
* @return the return string from the POST.
* @throws Exception if something goes wrong.
*/
public static String sendFilePost(Context context, String urlStr, File file, String user, String password) throws Exception {
BufferedOutputStream wr = null;
FileInputStream fis = null;
HttpURLConnection conn = null;
try {
long fileSize = file.length();
fis = new FileInputStream(file);
// Authenticator.setDefault(new Authenticator(){
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication("test", "test".toCharArray());
// }
// });
// if (urlStr.endsWith(SLASH)) {
// urlStr = urlStr + SLASH;
// }
urlStr = urlStr + "?name=" + file.getName();
conn = makeNewConnection(urlStr);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
// conn.setChunkedStreamingMode(0);
conn.setUseCaches(true);
// conn.setRequestProperty("Accept-Encoding", "gzip ");
// conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Type", "application/octet-stream");
conn.setRequestProperty("Content-Length", "" + fileSize);
// conn.setRequestProperty("Connection", "Keep-Alive");
if (user != null && password != null && user.trim().length() > 0 && password.trim().length() > 0) {
conn.setRequestProperty("Authorization", getB64Auth(user, password));
}
conn.connect();
wr = new BufferedOutputStream(conn.getOutputStream());
long bufferSize = Math.min(fileSize, maxBufferSize);
if (GPLog.LOG)
GPLog.addLogEntry(TAG, "BUFFER USED: " + bufferSize);
byte[] buffer = new byte[(int) bufferSize];
int bytesRead = fis.read(buffer, 0, (int) bufferSize);
long totalBytesWritten = 0;
while (bytesRead > 0) {
wr.write(buffer, 0, (int) bufferSize);
totalBytesWritten = totalBytesWritten + bufferSize;
if (totalBytesWritten >= fileSize)
break;
bufferSize = Math.min(fileSize - totalBytesWritten, maxBufferSize);
bytesRead = fis.read(buffer, 0, (int) bufferSize);
}
wr.flush();
int responseCode = conn.getResponseCode();
return getMessageForCode(context, responseCode,
context.getResources().getString(R.string.file_upload_completed_properly));
} catch (Exception e) {
throw e;
} finally {
if (wr != null)
wr.close();
if (fis != null)
fis.close();
if (conn != null)
conn.disconnect();
}
}
/**
* Download a bitmap from a given url.
* <p/>
* http://android-developers.blogspot.it/2010/07/multithreading-for-performance.html
*
* @param url the url.
* @return the downloaded bitmap or null.
*/
public static Bitmap downloadBitmap(String url) {
AndroidHttpClient client = null;
HttpGet getRequest = null;
try {
client = AndroidHttpClient.newInstance("Android");
getRequest = new HttpGet(url);
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
if (getRequest != null)
getRequest.abort();
} finally {
if (client != null) {
client.close();
}
}
return null;
}
// public static String uploadFile( Context context, String urlStr, File file, String user,
// String password ) {
// try {
// FileInputStream fileInputStream = new FileInputStream(file);
// String lineEnd = "\r\n";
// String twoHyphens = "--";
// String boundary = "*****";
// // ------------------ CLIENT REQUEST
// URL connectURL = new URL(urlStr);
// HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
// conn.setDoInput(true);
// conn.setDoOutput(true);
// conn.setUseCaches(false);
// conn.setRequestMethod("POST");
// conn.setRequestProperty("Connection", "Keep-Alive");
// conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
//
// DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
// dos.writeBytes(twoHyphens + boundary + lineEnd);
// dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" +
// file.getName() + "\"" + lineEnd);
// dos.writeBytes(lineEnd);
//
// // create a buffer of maximum size
// int bytesAvailable = fileInputStream.available();
// int maxBufferSize = 1024;
// int bufferSize = Math.min(bytesAvailable, maxBufferSize);
// byte[] buffer = new byte[bufferSize];
// // read file and write it into form...
// int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
// while( bytesRead > 0 ) {
// dos.write(buffer, 0, bufferSize);
// bytesAvailable = fileInputStream.available();
// bufferSize = Math.min(bytesAvailable, maxBufferSize);
// bytesRead = fileInputStream.read(buffer, 0, bufferSize);
// }
// dos.writeBytes(lineEnd);
// dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// fileInputStream.close();
// dos.flush();
//
// InputStream is = conn.getInputStream();
// int ch;
// StringBuffer b = new StringBuffer();
// while( (ch = is.read()) != -1 ) {
// b.append((char) ch);
// }
// String s = b.toString();
// Log.i("Response", s);
// dos.close();
// return s;
//
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// }
// public void executeMultipartPost() throws Exception {
//
// try {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// bm.compress(CompressFormat.JPEG, 75, bos);
// byte[] data = bos.toByteArray();
// HttpClient httpClient = new DefaultHttpClient();
// HttpPost postRequest = new HttpPost(
// "http://10.0.2.2/cfc/iphoneWebservice.cfc?returnformat=json&method=testUpload");
// ByteArrayBody bab = new ByteArrayBody(data, "forest.jpg");
// // File file= new File("/mnt/sdcard/forest.png");
// // FileBody bin = new FileBody(file);
// MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
// reqEntity.addPart("uploaded", bab);
// reqEntity.addPart("photoCaption", new StringBody("sfsdfsdf"));
// postRequest.setEntity(reqEntity);
// HttpResponse response = httpClient.execute(postRequest);
// BufferedReader reader = new BufferedReader(new
// InputStreamReader(response.getEntity().getContent(), "UTF-8"));
// String sResponse;
// StringBuilder s = new StringBuilder();
// while( (sResponse = reader.readLine()) != null ) {
// s = s.append(sResponse);
// }
// System.out.println("Response: " + s);
// } catch (Exception e) {
// Log.e(e.getClass().getName(), e.getMessage());
// }
// }
}