/******************************************************************************* * Created by Carlos Yaconi * Copyright 2015 Prey Inc. All rights reserved. * License: GPLv3 * Full license at "/LICENSE" ******************************************************************************/ package com.prey.net; import com.prey.PreyConfig; import com.prey.PreyLogger; import com.prey.PreyUtils; import com.prey.net.http.EntityFile; import com.prey.net.http.SimpleMultipartEntity; import com.prey.net.offline.OfflineDatasource; import com.prey.net.offline.OfflineDto; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; 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.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; public class UtilConnection { private static int RETRIES = 4; private static int[] ARRAY_RETRY_DELAY_MS =new int[]{1,2,3,4}; private static final String REQUEST_METHOD_PUT="PUT"; private static final String REQUEST_METHOD_POST="POST"; private static final String REQUEST_METHOD_GET="GET"; private static final String REQUEST_METHOD_DELETE="DELETE"; private static final boolean USE_CACHES=false; private static final int CONNECT_TIMEOUT=30000; private static final int READ_TIMEOUT=30000; private static String getCredentials(String user, String password) { return (Base64.encodeBytes((user + ":" + password).getBytes())); } private static String getUserAgent(PreyConfig preyConfig) { return "Prey/".concat(preyConfig.getPreyVersion()).concat(" (Android " + PreyUtils.getBuildVersionRelease() + ")"); } private static String getAuthorization(PreyConfig preyConfig) { //PreyLogger.d("getAuthorization:("+preyConfig.getApiKey()+",X)"); return "Basic " + getCredentials(preyConfig.getApiKey(), "X"); } private static String getAuthorization(String user,String pass) { //PreyLogger.d("getAuthorization:("+user+","+pass+")"); return "Basic " + getCredentials(user, pass); } public static final PreyHttpResponse connectionPut(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_PUT,contentType,null,null,null,null); } public static final PreyHttpResponse connectionGet(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_GET,contentType,null,null,null,null); } public static final PreyHttpResponse connectionGetAuthorization(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_GET,contentType,getAuthorization(preyConfig),null,null,null); } public static final PreyHttpResponse connectionGetAuthorization(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType,String user,String pass) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_GET,null, getAuthorization(user, pass),null,null,null); } public static final PreyHttpResponse connectionDelete(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_DELETE,contentType,null,null,null,null); } public static final PreyHttpResponse connectionDeleteAuthorization(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_DELETE,contentType,getAuthorization(preyConfig),null,null,null); } public static final PreyHttpResponse connectionPost(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_POST,contentType,null,null,null,null); } public static final PreyHttpResponse connectionPostAuthorization(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_POST,contentType,getAuthorization(preyConfig),null,null,null); } public static final PreyHttpResponse connectionPostAuthorization(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType,List<EntityFile> entityFiles) throws Exception { return connection(preyConfig, uri, params, REQUEST_METHOD_POST, contentType,getAuthorization(preyConfig), null,entityFiles,null); } public static final PreyHttpResponse connectionPostAuthorizationStatus(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType,String status) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_POST,contentType,getAuthorization(preyConfig),status,null,null); } public static final PreyHttpResponse connectionPostAuthorizationCorrelationId(PreyConfig preyConfig,String uri, Map<String, String> params, String contentType,String status,String correlationId) throws Exception { return connection(preyConfig,uri,params,REQUEST_METHOD_POST,contentType,getAuthorization(preyConfig),status,null,correlationId); } public static final PreyHttpResponse connection(PreyConfig preyConfig,String uri, Map<String, String> params,String requestMethod,String contentType,String authorization,String status,List<EntityFile> entityFiles,String correlationId) throws Exception { PreyHttpResponse response=null; URL url = new URL(uri); HttpURLConnection connection=null; int retry = 0; boolean delay=false; PreyLogger.d("uri:"+uri); if(params!=null){ Iterator<String> ite=params.keySet().iterator(); while (ite.hasNext()){ String key=ite.next(); PreyLogger.d("["+key+"]:"+params.get(key)); } } SimpleMultipartEntity multiple=new SimpleMultipartEntity(); SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmZ"); List <ByteArrayOutputStream> listOutputStream = new ArrayList<>(); try{ do { if (delay) { Thread.sleep(ARRAY_RETRY_DELAY_MS[retry]*1000); } if (uri.indexOf("https:")>=0) { connection = (HttpsURLConnection) url.openConnection(); }else{ connection = (HttpURLConnection) url.openConnection(); } ByteArrayOutputStream out = new ByteArrayOutputStream(); connection.setRequestMethod(requestMethod); connection.setRequestProperty("Accept", "*/*"); if(contentType!=null) { connection.addRequestProperty("Content-Type", contentType); } if (authorization!=null) { connection.addRequestProperty("Authorization", authorization); //PreyLogger.i("Authorization:"+authorization); } if (status!=null) { connection.addRequestProperty("X-Prey-Status", status); //PreyLogger.i("X-Prey-Status:"+status); } if (correlationId!=null) { connection.addRequestProperty("X-Prey-Correlation-ID", correlationId); PreyLogger.i("X-Prey-Correlation-ID:"+correlationId); String deviceId=preyConfig.getDeviceId(); connection.addRequestProperty("X-Prey-Device-ID", deviceId); PreyLogger.i("X-Prey-Device-ID:"+deviceId); connection.addRequestProperty("X-Prey-State", status); PreyLogger.i("X-Prey-State:"+status); } connection.addRequestProperty("User-Agent", getUserAgent(preyConfig)); if (entityFiles==null&&(params!=null&¶ms.size()>0)){ OutputStream os = connection.getOutputStream(); DataOutputStream dos = new DataOutputStream( os ); dos.writeBytes(getPostDataString(params)); } if( entityFiles!=null&&entityFiles.size()>0 ) { for(Map.Entry<String, String> entry : params.entrySet()){ String key= entry.getKey(); String value=null; try{ value= entry.getValue() ; }catch(Exception e){ } if(value==null){ value=""; } multiple.addPart(key,value); } for(int i=0;entityFiles!=null&&i<entityFiles.size();i++) { EntityFile entityFile = entityFiles.get(i); boolean isLast = ((i + 1) == entityFiles.size() ? true : false); ByteArrayOutputStream outputStream=multiple.addPart(entityFile.getType(), entityFile.getName(), entityFile.getFile(), entityFile.getMimeType(), isLast); listOutputStream.add(outputStream); } connection.setRequestProperty("Content-Length", "" + multiple.getContentLength()); connection.setRequestProperty("Content-Type", multiple.getContentType()); OutputStream os = connection.getOutputStream(); multiple.writeTo(os); } int responseCode=connection.getResponseCode(); String responseMessage = connection.getResponseMessage(); PreyLogger.i("responseCode:"+responseCode+" responseMessage:"+responseMessage+" uri:"+uri); switch (responseCode) { case HttpURLConnection.HTTP_CREATED: PreyLogger.d(uri + " **CREATED**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_OK: PreyLogger.d(uri + " **OK**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_CONFLICT: PreyLogger.d(uri + " **CONFLICT**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_FORBIDDEN: PreyLogger.d(uri + " **FORBIDDEN**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_MOVED_TEMP: PreyLogger.d(uri + " **MOVED_TEMP**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case 422: PreyLogger.d(uri + " **422**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_BAD_GATEWAY: PreyLogger.d(uri + " **BAD_GATEWAY**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_INTERNAL_ERROR: PreyLogger.d(uri + " **INTERNAL_ERROR**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_NOT_FOUND: PreyLogger.d(uri + " **NOT_FOUND**"); response = convertPreyHttpResponse(responseCode,connection); retry = RETRIES; break; case HttpURLConnection.HTTP_GATEWAY_TIMEOUT: PreyLogger.d(uri + " **gateway timeout**"); break; case HttpURLConnection.HTTP_UNAVAILABLE: PreyLogger.d(uri + "**unavailable**"); break; default: PreyLogger.d(uri + " **unknown response code**."); break; } connection.disconnect(); retry++; if(retry <= RETRIES) { PreyLogger.i("Failed retry " + retry + "/" + RETRIES); } delay = true; } while (retry < RETRIES); }catch(Exception e){ PreyLogger.i("error util:"+e.getMessage()); } if(response==null||(response!=null&& !(response.getStatusCode()==200||response.getStatusCode()==201))) { OfflineDatasource datasource = new OfflineDatasource(preyConfig.getContext()); if(response!=null) { PreyLogger.i("code:" + response.getStatusCode()); } PreyLogger.i("uri:"+uri+" status:"+status); OfflineDto offline=new OfflineDto(); offline.setOfflineId(sdf.format(new Date())); offline.setUrl(uri); offline.setContentType(contentType); offline.setAuthorization(authorization); offline.setStatus(status); offline.setCorrelationId(correlationId); offline.setParameters(params.toString()); offline.setRequestMethod(requestMethod); if (entityFiles != null && entityFiles.size() > 0) { JSONArray array=new JSONArray(); for (int i = 0; entityFiles != null && i < entityFiles.size(); i++) { EntityFile entityFile = entityFiles.get(i); JSONObject json=new JSONObject(); json.put("idFile",entityFile.getIdFile()); json.put("type",entityFile.getType()); json.put("name",entityFile.getName()); json.put("mimeType",entityFile.getMimeType()); json.put("length",entityFile.getLength()); ByteArrayOutputStream outputStream=listOutputStream.get(i); PreyLogger.i("idFile:"+entityFile.getIdFile()+" json:"+json.toString()); array.put(json); saveFile(entityFile.getIdFile(),outputStream); } PreyLogger.i("files:"+array.toString()); offline.setFiles(array.toString()); offline.setOfflineId(sdf.format(new Date())+"_report"); } PreyLogger.i("id:"+offline.getOfflineId()+" url:"+offline.getUrl()); PreyLogger.i("id:"+offline.getOfflineId()+" requestMethod:" + requestMethod); PreyLogger.i("id:"+offline.getOfflineId()+" contentType:" + contentType); PreyLogger.i("id:"+offline.getOfflineId()+" authorization:" + authorization); PreyLogger.i("id:"+offline.getOfflineId()+" status:" + status); PreyLogger.i("id:"+offline.getOfflineId()+" correlationId:" + correlationId); PreyLogger.i("id:"+offline.getOfflineId()+" files:" + offline.getFiles()); datasource.createOffline(offline); } return response; } private static void saveFile(String idFile,ByteArrayOutputStream outputStream){ FileOutputStream fileOutputStream = null; ByteArrayInputStream byteArrayInputStream = null; try { File preyDirectory = new File("/sdcard/prey/"); preyDirectory.mkdirs(); PreyLogger.i("idFile:"+idFile+" byteArrayInputStream null:"+(byteArrayInputStream==null)); File file=new File("/sdcard/prey/file" + idFile+".jpg"); fileOutputStream = new FileOutputStream(file); if (!file.exists()) { file.createNewFile(); } fileOutputStream.write(outputStream.toByteArray()); fileOutputStream.flush(); } catch (Exception e) { PreyLogger.i("Error:"+e.getMessage()); PreyLogger.e("Error:"+e.getMessage(),e); } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { } } if (byteArrayInputStream != null) { try { byteArrayInputStream.close(); } catch (IOException e) { } } } } private static PreyHttpResponse convertPreyHttpResponse(int responseCode,HttpURLConnection connection)throws Exception { StringBuffer sb = new StringBuffer(); if(responseCode==200||responseCode==201) { InputStream input = connection.getInputStream(); if (input != null) { BufferedReader in = new BufferedReader(new InputStreamReader(input)); String decodedString; while ((decodedString = in.readLine()) != null) { sb.append(decodedString); sb.append('\r'); } in.close(); } PreyLogger.d(sb.toString()); } Map<String, List<String>> mapHeaderFields=connection.getHeaderFields(); connection.disconnect(); return new PreyHttpResponse(responseCode,sb.toString(),mapHeaderFields); } public static HttpURLConnection connectionPostJson(PreyConfig preyConfig,String uri, JSONObject jsonParam) { return connectionPostJson(preyConfig,uri,jsonParam,null); } public static HttpURLConnection connectionPostJsonAuthorization(PreyConfig preyConfig,String uri, JSONObject jsonParam) { return connectionPostJson(preyConfig,uri,jsonParam,"Basic " + getCredentials(preyConfig.getApiKey(), "X")); } public static HttpURLConnection connectionPostJson(PreyConfig preyConfig,String uri, JSONObject jsonParam, String authorization) { HttpURLConnection connection=null; int httpResult = -1; try { URL url = new URL(uri); PreyLogger.i("postJson page:" + uri); connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod(REQUEST_METHOD_POST); connection.setUseCaches(USE_CACHES); connection.setConnectTimeout(CONNECT_TIMEOUT); connection.setReadTimeout(READ_TIMEOUT); connection.setRequestProperty("Content-Type", "application/json"); if (authorization!=null) connection.addRequestProperty("Authorization", authorization); connection.addRequestProperty("User-Agent",getUserAgent(preyConfig)); connection.addRequestProperty("Origin", "android:com.prey"); connection.connect(); PreyLogger.d("jsonParam.toString():" + jsonParam.toString()); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); out.write(jsonParam.toString()); out.close(); httpResult = connection.getResponseCode(); PreyLogger.i("postJson responseCode:"+httpResult); } catch (Exception e) { PreyLogger.e("postJson error:" + e.getMessage(), e); } return connection; } private static String getPostDataString(Map<String, String> params) throws UnsupportedEncodingException{ StringBuilder result = new StringBuilder(); boolean first = true; for(Map.Entry<String, String> entry : params.entrySet()){ if (first) first = false; else result.append("&"); result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); try { result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); }catch (Exception e){ result.append(URLEncoder.encode("", "UTF-8")); } } return result.toString(); } public static int uploadFile(PreyConfig preyConfig,String page, File file,long total){ int responseCode =0; HttpURLConnection connection = null; OutputStream output = null; InputStream input =null; FileInputStream fileInput=null; PreyLogger.i("page:"+page+" upload:"+file.getName()+" length:"+file.length()+" total:"+total); try { URL url=new URL(page); connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.addRequestProperty("Origin", "android:com.prey"); connection.addRequestProperty("Content-Type", "application/octet-stream"); connection.addRequestProperty("User-Agent", getUserAgent(preyConfig)); if(total>0){ connection.addRequestProperty("X-Prey-Upload-Resumable",""+total); connection.setRequestProperty("Content-Length", "" + (file.length()-total)); PreyLogger.i("Content-Length:"+(file.length()-total)); }else{ connection.setRequestProperty("Content-Length", "" + file.length()); } output = connection.getOutputStream(); fileInput=new FileInputStream(file); input = new BufferedInputStream(fileInput); int maxByte=4096; byte[] buffer = new byte[maxByte]; int length; long dif=total-maxByte; long read=0; if (total>0) { int maxByte2=4096; byte[] buffer2 = new byte[maxByte2]; do { length=0; if (total<maxByte2) { buffer2 = new byte[(int)total]; } length = input.read(buffer2); read=read+length; total=total-length; if (total<=0) break; PreyLogger.i("uploadFile total:"+total+" length:"+length+" read:"+read); }while(total > 0); } PreyLogger.i("uploadFile read:"+read); while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } output.flush(); String responseMessage = connection.getResponseMessage(); responseCode = connection.getResponseCode(); PreyLogger.i("uploadFile responseCode:"+responseCode+" responseMessage:"+responseMessage); } catch (Exception e) { PreyLogger.e("error upload:"+e.getMessage(),e); responseCode=0; } finally { try { if(input != null) { input.close(); } } catch (IOException e) { } try { if(fileInput != null) { fileInput.close(); } } catch (IOException e) { } try { if(output != null) { output.close(); } } catch (IOException e) { } if(connection != null) { connection.disconnect(); } } return responseCode; } }