package ar.rulosoft.navegadores; import android.content.Context; import android.util.Log; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import okhttp3.CookieJar; import okhttp3.FormBody; import okhttp3.Headers; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; /** * @author Raul, nulldev, xtj-9182 */ public class Navigator { public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"; public static int connectionTimeout = 10; public static int writeTimeout = 10; public static int readTimeout = 30; public static Navigator navigator; private static CookieJar cookieJar; private OkHttpClient httpClient; private ArrayList<Parameter> parameters = new ArrayList<>(); private ArrayList<Parameter> headers = new ArrayList<>(); public Navigator(Context context) throws Exception { if (httpClient == null) { cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context)); httpClient = new OkHttpClientConnectionChecker.Builder() //.addInterceptor(new UserAgentInterceptor(USER_AGENT)) .addInterceptor(new CFInterceptor()) .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .cookieJar(cookieJar) .build(); } } public static HashMap<String, String> getFormParamsFromSource(String inSource) throws Exception { HashMap<String, String> ParametrosForm = new HashMap<>(); Pattern p = Pattern.compile("<[F|f]orm([\\s|\\S]+?)</[F|f]orm>"); Matcher m = p.matcher(inSource); while (m.find()) { Pattern p1 = Pattern.compile("<[I|i]nput type=[^ ]* name=['|\"]([^\"']*)['|\"] value=['|\"]([^'\"]*)['|\"]"); Matcher m1 = p1.matcher(m.group()); while (m1.find()) { ParametrosForm.put(m1.group(1), m1.group(2)); } } return ParametrosForm; } public static CookieJar getCookieJar() { return cookieJar; } public void setCookieJar(CookieJar cookieJar) { httpClient = new OkHttpClientConnectionChecker.Builder() //.addInterceptor(new UserAgentInterceptor(USER_AGENT)) .addInterceptor(new CFInterceptor()) .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .cookieJar(cookieJar) .build(); Navigator.cookieJar = cookieJar; } public String get(String web) throws Exception { return this.get(web, connectionTimeout, writeTimeout, readTimeout); } public String get(String web, int connectionTimeout, int writeTimeout, int readTimeout) throws Exception { // copy will share the connection pool with httpclient // NEVER create new okhttp clients that aren't sharing the same connection pool // see: https://github.com/square/okhttp/issues/2636 OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } public String getWithTimeout(String web) throws Exception { return this.getWithTimeout(web, "", connectionTimeout, writeTimeout, readTimeout); } public String getWithTimeout(String web, String referer) throws Exception { return this.getWithTimeout(web, referer, connectionTimeout, writeTimeout, readTimeout); } private String getWithTimeout(String web, String referer, int connectionTimeout, int writeTimeout, int readTimeout) throws Exception { // copy will share the connection pool with httpclient // NEVER create new okhttp clients that aren't sharing the same connection pool // see: https://github.com/square/okhttp/issues/2636 OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); if (!referer.isEmpty()) { addHeader("Referer", referer); } Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); int i = 0; int timeout = 250; while (!response.isSuccessful()) { Log.i("Nav", "source is empty, waiting for " + timeout + " ms before retrying ..."); i++; Thread.sleep(timeout); response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (i < 3) timeout += 250; else timeout += 500; if (i == 5) { Log.i("Nav", "couldn't get a source from " + web + " :("); break; } } if (response.isSuccessful()) { if(timeout > 250) Log.i("Nav", "timeout of " + timeout + " ms worked got a source"); return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } public InputStream getStream(String web) throws Exception { // copy will share the connection pool with httpclient // NEVER create new okhttp clients that aren't sharing the same connection pool // see: https://github.com/square/okhttp/issues/2636 OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return response.body().byteStream(); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); throw new Exception("Can't get stream"); } } public String getAndReturnResponseCodeOnFailure(String web) throws Exception { return this.getAndReturnResponseCodeOnFailure(web, connectionTimeout, writeTimeout, readTimeout); } private String getAndReturnResponseCodeOnFailure(String web, int connectionTimeout, int writeTimeout, int readTimeout) throws Exception { // copy will share the connection pool with httpclient // NEVER create new okhttp clients that aren't sharing the same connection pool // see: https://github.com/square/okhttp/issues/2636 OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { String responseCode = "" + response.code(); Log.e("Nav", "response unsuccessful: " + responseCode + " " + response.message() + " web: " + web); response.body().close(); return responseCode; } } public String get(String web, String referer, Interceptor interceptor) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .addInterceptor(interceptor) .build(); addHeader("Referer", referer); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } public String get(String web, Interceptor interceptor) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .addInterceptor(interceptor) .build(); addHeader("Content-Encoding", "deflate"); addHeader("Accept-Encoding", "deflate"); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } public String get(String web, String referer) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); addHeader("Referer", referer); Response response = copy.newCall(new Request.Builder().url(web).headers(getHeaders()).build()).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } @Deprecated public String get(String ip, String path, String host) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); addHeader("Host", host); Request request = new Request.Builder() .url("http://" + ip + path) .headers(getHeaders()) .build(); Response response = copy.newCall(request).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message()); response.body().close(); return ""; } } public String post(String web) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url(web) .headers(getHeaders()) .method("POST", getPostParams()) .build(); Response response = copy.newCall(request).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } public String post(String web, RequestBody formParams) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url(web) .headers(getHeaders()) .method("POST", formParams) .build(); Response response = copy.newCall(request).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message() + " web: " + web); response.body().close(); return ""; } } @Deprecated public String post(String ip, String path, String host) throws Exception { OkHttpClient copy = httpClient.newBuilder() .connectTimeout(connectionTimeout, TimeUnit.SECONDS) .writeTimeout(writeTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); addHeader("Host", host); Request request = new Request.Builder() .url("http://" + ip + path) .headers(getHeaders()) .method("POST", getPostParams()) .build(); Response response = copy.newCall(request).execute(); if (response.isSuccessful()) { return formatResponseBody(response.body()); } else { Log.e("Nav", "response unsuccessful: " + response.code() + " " + response.message()); response.body().close(); return ""; } } public String formatResponseBody(ResponseBody responseBody) throws IOException { return responseBody.string().replaceAll("(\n|\r)", ""); } private RequestBody getPostParams() throws Exception { FormBody.Builder builder = new FormBody.Builder(); for (Parameter p : parameters) { builder.add(p.getKey(), p.getValue()); } return builder.build(); } public void addPost(String key, String value) { parameters.add(new Parameter(key, value)); } public HashMap<String, String> getFormParams(String url) throws Exception { String source = this.get(url); HashMap<String, String> ParametrosForm = new HashMap<>(); Pattern p = Pattern.compile("<[F|f]orm([\\s|\\S]+?)</[F|f]orm>"); Matcher m = p.matcher(source); while (m.find()) { Pattern p1 = Pattern.compile("<[I|i]nput type=[^ ]* name=['|\"]([^\"']*)['|\"] value=['|\"]([^'\"]*)['|\"]"); Matcher m1 = p1.matcher(m.group()); while (m1.find()) { ParametrosForm.put(m1.group(1), m1.group(2)); } } return ParametrosForm; } public Headers getHeaders() { Headers.Builder builder = new Headers.Builder(); builder.add("User-Agent", USER_AGENT);//this is used all the time for (Parameter p : headers) { builder.add(p.getKey(), p.getValue()); } headers.clear();//and those are volatile return builder.build(); } public void addHeader(String key, String value) { headers.add(new Parameter(key, value)); } public void flushParameter() { parameters = new ArrayList<>(); } public OkHttpClient getHttpClient() { return httpClient; } public void dropAllCalls() { httpClient.dispatcher().cancelAll(); } } /** * Adds user agent to any client the interceptor is attached to. */ class UserAgentInterceptor implements Interceptor { private String userAgent; public UserAgentInterceptor(String userAgent) { this.userAgent = userAgent; } @Override public Response intercept(Chain chain) throws IOException { return chain.proceed(chain.request().newBuilder() .header("User-Agent", userAgent) .build()); } public String getUserAgent() { return userAgent; } public void setUserAgent(String userAgent) { this.userAgent = userAgent; } }