/* * Project: NextGIS Mobile * Purpose: Mobile GIS for Android. * Author: Dmitry Baryshnikov (aka Bishop), [email protected] * Author: NikitaFeodonit, [email protected] * Author: Stanislav Petriakov, [email protected] * ***************************************************************************** * Copyright (c) 2012-2018 NextGIS, [email protected] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser Public License for more details. * * You should have received a copy of the GNU Lesser Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.nextgis.maplib.util; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import com.nextgis.maplib.R; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.nextgis.maplib.util.Constants.TAG; public class NetworkUtil { private static final String IP_ADDRESS = "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))(:[0-9]{1,5})?"; public static final String URL_PATTERN = "^(?i)((ftp|https?)://)?(([\\da-z.-]+)\\.([a-z.]{2,6})|" + IP_ADDRESS + ")(:[0-9]{1,5})?(/\\S*)?$"; public final ConnectivityManager mConnectionManager; public final TelephonyManager mTelephonyManager; protected long mLastCheckTime; protected Context mContext; public final static int TIMEOUT_CONNECTION = 10000; public final static int TIMEOUT_SOCKET = 240000; // 180 sec public final static int ERROR_AUTH = -401; public final static int ERROR_NETWORK_UNAVAILABLE = -1; public final static int ERROR_CONNECT_FAILED = 0; public final static int ERROR_DOWNLOAD_DATA = 1; public final static String HTTP_GET = "GET"; public final static String HTTP_POST = "POST"; public final static String HTTP_PUT = "PUT"; public final static String HTTP_DELETE = "DELETE"; public NetworkUtil(Context context) { mConnectionManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); mLastCheckTime = Constants.NOT_FOUND; mContext = context; } public synchronized boolean isNetworkAvailable() { if (mConnectionManager == null) { return false; } NetworkInfo info = mConnectionManager.getActiveNetworkInfo(); if (info == null) { return false; } return info.isConnected(); } public static HttpURLConnection getHttpConnection( String method, String targetURL, String username, String password) throws IOException { URL url = new URL(targetURL); // Open a HTTP connection to the URL HttpURLConnection conn = (HttpURLConnection) url.openConnection(); String basicAuth = getHTTPBaseAuth(username, password); if (null != basicAuth) { conn.setRequestProperty("Authorization", basicAuth); } conn.setRequestProperty("User-Agent", Constants.APP_USER_AGENT); // Allow Inputs conn.setDoInput(true); // Don't use a cached copy. conn.setUseCaches(false); // Use a post method. if(method.length() > 0) conn.setRequestMethod(method); conn.setConnectTimeout(TIMEOUT_CONNECTION); conn.setReadTimeout(TIMEOUT_SOCKET); conn.setRequestProperty("Accept", "*/*"); return isValidUri(targetURL) ? conn : null; } public static boolean isValidUri(String url) { Pattern pattern = Pattern.compile(URL_PATTERN); Matcher match = pattern.matcher(url); return match.matches(); } public static String getHTTPBaseAuth(String username, String password){ if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) { return "Basic " + Base64.encodeToString( (username + ":" + password).getBytes(), Base64.NO_WRAP); } return null; } public static String responseToString(final InputStream is) throws IOException { if (is == null) { return null; } byte[] buffer = new byte[Constants.IO_BUFFER_SIZE]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); FileUtil.copyStream(is, baos, buffer, Constants.IO_BUFFER_SIZE); byte[] bytesReceived = baos.toByteArray(); baos.close(); is.close(); return new String(bytesReceived); } public static void getStream( String targetURL, String username, String password, OutputStream outputStream) throws IOException { final HttpURLConnection conn = getHttpConnection("GET", targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get stream: " + targetURL); throw new IOException("Connection is null"); } int responseCode = conn.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { if(Constants.DEBUG_MODE) Log.d(TAG, "Problem execute getStream: " + targetURL + " HTTP response: " + responseCode + " username: " + username); throw new IOException("Response code is " + responseCode); } byte data[] = new byte[Constants.IO_BUFFER_SIZE]; InputStream is = conn.getInputStream(); FileUtil.copyStream(is, outputStream, data, Constants.IO_BUFFER_SIZE); outputStream.close(); } protected static HttpResponse getHttpResponse( HttpURLConnection conn, boolean readErrorResponseBody) throws IOException { String method = conn.getRequestMethod(); int code = conn.getResponseCode(); String message = conn.getResponseMessage(); HttpResponse response = new HttpResponse(code, message); if (!(code == HttpURLConnection.HTTP_OK || (code == HttpURLConnection.HTTP_CREATED && method.equals(HTTP_POST)))) { if (Constants.DEBUG_MODE) { String url = conn.getURL().toExternalForm(); if ("Keep-Alive".equals(conn.getRequestProperty("Connection"))) method = "postFile(), targetURL"; Log.d(TAG, "Problem execute " + method + ": " + url + " HTTP response: " + code); } if (readErrorResponseBody) response.setResponseBody(responseToString(conn.getErrorStream())); return response; } String body = responseToString(conn.getInputStream()); if (null == body) { response.setResponseCode(ERROR_DOWNLOAD_DATA); response.setResponseMessage(null); return response; } response.setResponseBody(body); response.setOk(true); return response; } public static HttpResponse get( String targetURL, String username, String password, boolean readErrorResponseBody) throws IOException { final HttpURLConnection conn = getHttpConnection(HTTP_GET, targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get connection object: " + targetURL); return new HttpResponse(ERROR_CONNECT_FAILED); } return getHttpResponse(conn, readErrorResponseBody); } public static HttpResponse post( String targetURL, String payload, String username, String password, boolean readErrorResponseBody) throws IOException { final HttpURLConnection conn = getHttpConnection(HTTP_POST, targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get connection object: " + targetURL); return new HttpResponse(ERROR_CONNECT_FAILED); } conn.setRequestProperty("Content-type", "application/json"); // Allow Outputs conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); writer.write(payload); writer.flush(); writer.close(); os.close(); return getHttpResponse(conn, readErrorResponseBody); } public static HttpResponse delete( String targetURL, String username, String password, boolean readErrorResponseBody) throws IOException { final HttpURLConnection conn = getHttpConnection(HTTP_DELETE, targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get connection object: " + targetURL); return new HttpResponse(ERROR_CONNECT_FAILED); } return getHttpResponse(conn, readErrorResponseBody); } public static HttpResponse put( String targetURL, String payload, String username, String password, boolean readErrorResponseBody) throws IOException { final HttpURLConnection conn = getHttpConnection(HTTP_PUT, targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get connection object: " + targetURL); return new HttpResponse(ERROR_CONNECT_FAILED); } conn.setRequestProperty("Content-type", "application/json"); // Allow Outputs conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); writer.write(payload); writer.flush(); writer.close(); os.close(); return getHttpResponse(conn, readErrorResponseBody); } public static HttpResponse postFile( String targetURL, String fileName, File file, String fileMime, String username, String password, boolean readErrorResponseBody) throws IOException { final String lineEnd = "\r\n"; final String twoHyphens = "--"; final String boundary = "**nextgis**"; //------------------ CLIENT REQUEST FileInputStream fileInputStream = new FileInputStream(file); // open a URL connection to the Servlet HttpURLConnection conn = getHttpConnection(HTTP_POST, targetURL, username, password); if (null == conn) { if (Constants.DEBUG_MODE) Log.d(TAG, "Error get connection object: " + targetURL); return new HttpResponse(ERROR_CONNECT_FAILED); } conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); // Allow Outputs conn.setDoOutput(true); DataOutputStream dos = new DataOutputStream(conn.getOutputStream()); dos.writeBytes(twoHyphens + boundary + lineEnd); dos.writeBytes( "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"" + lineEnd); if (!TextUtils.isEmpty(fileMime)) { dos.writeBytes("Content-Type: " + fileMime + lineEnd); } dos.writeBytes(lineEnd); byte[] buffer = new byte[Constants.IO_BUFFER_SIZE]; FileUtil.copyStream(fileInputStream, dos, buffer, Constants.IO_BUFFER_SIZE); dos.writeBytes(lineEnd); dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); fileInputStream.close(); dos.flush(); dos.close(); return getHttpResponse(conn, readErrorResponseBody); } public static String getError( Context context, int responseCode) { switch (responseCode) { case ERROR_AUTH: return context.getString(R.string.error_auth); case ERROR_NETWORK_UNAVAILABLE: return context.getString(R.string.error_network_unavailable); case ERROR_CONNECT_FAILED: return context.getString(R.string.error_connect_failed); case ERROR_DOWNLOAD_DATA: return context.getString(R.string.error_download_data); case HttpURLConnection.HTTP_UNAUTHORIZED: return context.getString(R.string.error_401); case HttpURLConnection.HTTP_FORBIDDEN: return context.getString(R.string.error_403); case HttpURLConnection.HTTP_NOT_FOUND: return context.getString(R.string.error_404); case HttpURLConnection.HTTP_INTERNAL_ERROR: return context.getString(R.string.error_500); default: return context.getString(R.string.error_500); } } }