Port HttpJsonRequest to OkHttp

* Make HttpJsonRequest a singleton
* Use an Interceptor to add the Authorization header
* Remove now unused getUsername/getPassword methods from API
This commit is contained in:
Daniel Schaal 2015-09-19 12:56:49 +02:00
parent 08f0acc1c9
commit 5c996bba45
12 changed files with 135 additions and 177 deletions

View file

@ -64,6 +64,7 @@ dependencies {
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.jakewharton:butterknife:5.1.+'
compile 'com.sothree.slidinguppanel:library:3.1.1'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'de.greenrobot:eventbus:2.2.1'
compile 'de.greenrobot:greendao:2.0.0'
compile 'de.greenrobot:greendao-generator:2.0.0'

View file

@ -316,7 +316,7 @@ public class LoginDialogFragment extends DialogFragment implements IAccountImpor
protected Integer doInBackground(Void... params) {
try {
String _version = OwnCloudReaderMethods.GetVersionNumber(getActivity(), username, password, oc_root_path);
String _version = OwnCloudReaderMethods.GetVersionNumber(getActivity(), oc_root_path);
if(_version != null)
{
_version = _version.replace(".", "");

View file

@ -218,10 +218,7 @@ public class NewFeedActivity extends AppCompatActivity {
API api = new APIv2(NewFeedActivity.this);
try {
int status = HttpJsonRequest.performCreateFeedRequest(api.getFeedUrl(),
api.getUsername(),
api.getPassword(),
NewFeedActivity.this,
int status = HttpJsonRequest.getInstance().performCreateFeedRequest(api.getFeedUrl(),
mUrlToFeed, mFolderId);
if(status == 200) {

View file

@ -9,6 +9,8 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import de.luhmer.owncloudnewsreader.reader.HttpJsonRequest;
/**
* Created by daniel on 12.07.15.
*/
@ -17,6 +19,7 @@ public class NewsReaderApplication extends Application {
public void onCreate() {
super.onCreate();
initImageLoader();
HttpJsonRequest.init(this);
}
public void initImageLoader() {

View file

@ -793,7 +793,7 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements
if(username != null) {
_Reader = new OwnCloud_Reader();
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, this, onAsyncTaskGetVersionFinished, username, password);
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, this, onAsyncTaskGetVersionFinished);
Toast.makeText(this, getString(R.string.toast_GettingMoreItems), Toast.LENGTH_SHORT).show();
}

View file

@ -21,27 +21,27 @@
package de.luhmer.owncloudnewsreader.reader;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
@ -51,32 +51,90 @@ import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager;
import de.luhmer.owncloudnewsreader.ssl.TLSSocketFactory;
public class HttpJsonRequest {
//private static final String TAG = "HttpJsonRequest";
private static final String TAG = "HttpJsonRequest";
@SuppressLint("DefaultLocale")
public static InputStream PerformJsonRequest(String urlString, HashMap<String,String> nameValuePairs, final String username, final String password, Context context) throws Exception
{
if(nameValuePairs != null) {
urlString += getUrlEncodedString(nameValuePairs);
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static HttpJsonRequest instance;
public static void init(Context context) {
if(instance != null)
throw new IllegalStateException("Already initialized");
instance = new HttpJsonRequest(context);
}
public static HttpJsonRequest getInstance() {
if(instance == null)
throw new IllegalStateException("Must be initialized first");
return instance;
}
private final OkHttpClient client;
private HttpJsonRequest(Context context) {
client = new OkHttpClient();
// set location of the keystore
MemorizingTrustManager.setKeyStoreFile("private", "sslkeys.bks");
// register MemorizingTrustManager for HTTPS
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, MemorizingTrustManager.getInstanceList(context),
new java.security.SecureRandom());
// enables TLSv1.1/1.2 for Jelly Bean Devices
TLSSocketFactory tlsSocketFactory = new TLSSocketFactory(sc);
client.setSslSocketFactory(tlsSocketFactory);
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
URL url = new URL(API.validateURL(urlString));
client.setConnectTimeout(10000, TimeUnit.MILLISECONDS);
client.setReadTimeout(120, TimeUnit.SECONDS);
HttpURLConnection urlConnection = getUrlConnection(url, context, username, password);
//HttpsURLConnection urlConnection = null;
// disable hostname verification, when preference is set
// (this still shows a certification dialog, which requires user interaction!)
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
if(sp.getBoolean(SettingsActivity.CB_DISABLE_HOSTNAME_VERIFICATION_STRING, false))
client.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
client.interceptors().add(new AuthorizationInterceptor(sp));
}
private class AuthorizationInterceptor implements Interceptor {
private SharedPreferences sp;
// Define an array of pins. One of these must be present
// in the certificate chain you receive. A pin is a hex-encoded
// hash of a X.509 certificate's SubjectPublicKeyInfo. A pin can
// be generated using the provided pin.py script:
// python ./tools/pin.py certificate_file.pem
public AuthorizationInterceptor(SharedPreferences sp) {
this.sp = sp;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//String[] pins = new String[] {"f30012bbc18c231ac1a44b788e410ce754182513"};
//HttpsURLConnection urlConnection = PinningHelper.getPinnedHttpsURLConnection(context, pins, url);
request = request.newBuilder()
.addHeader("Authorization",Credentials.basic(sp.getString(SettingsActivity.EDT_USERNAME_STRING, null),sp.getString(SettingsActivity.EDT_PASSWORD_STRING, null)))
.build();
return chain.proceed(request);
}
}
public InputStream PerformJsonRequest(String urlString, HashMap<String,String> nameValuePairs) throws Exception
{
HttpUrl.Builder urlBuilder = HttpUrl.parse(API.validateURL(urlString)).newBuilder();
if(nameValuePairs != null) {
for(String key: nameValuePairs.keySet())
urlBuilder.addQueryParameter(key,nameValuePairs.get(key));
}
Request request = new Request.Builder()
.url(urlBuilder.build())
.get()
.build();
//http://nelenkov.blogspot.de/2011/12/using-custom-certificate-trust-store-on.html
//http://stackoverflow.com/questions/5947162/https-and-self-signed-certificate-issue
@ -84,126 +142,45 @@ public class HttpJsonRequest {
//http://stackoverflow.com/questions/859111/how-do-i-accept-a-self-signed-certificate-with-a-java-httpsurlconnection
//http://developer.android.com/training/articles/security-ssl.html
urlConnection.setDoOutput(false);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
//urlConnection.setFollowRedirects(true);
urlConnection.setUseCaches(false);
urlConnection.setConnectTimeout(10000);
urlConnection.setReadTimeout(120000);//2min
urlConnection.setRequestProperty("Content-Type","application/json");
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
// CookieHandler.setDefault(new CookieManager());
Response response = client.newCall(request).execute();
urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0");
//urlConnection.setRequestProperty("Host", "de.luhmer.ownCloudNewsReader");
urlConnection.connect();
int HttpResult = urlConnection.getResponseCode();
if(HttpResult == HttpURLConnection.HTTP_OK) {
return urlConnection.getInputStream();
if(response.isSuccessful()) {
return response.body().byteStream();
} else {
throw new Exception(urlConnection.getResponseMessage());
throw new Exception(response.message());
}
}
private static String getUrlEncodedString(HashMap<String, String> nameValuePairs) throws UnsupportedEncodingException {
String urlString = "";
for(Entry<String,String> entry: nameValuePairs.entrySet()) {
urlString += String.format("&%s=%s", URLEncoder.encode(entry.getKey(), "UTF-8"), URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return urlString;
public int performCreateFeedRequest(String urlString, String feedUrl, long folderId) throws Exception {
HttpUrl url = HttpUrl.parse(API.validateURL(urlString)).newBuilder()
.setQueryParameter("url", feedUrl)
.setQueryParameter("folderId", String.valueOf(folderId))
.build();
Request request = new Request.Builder()
.url(url)
.post(RequestBody.create(JSON, ""))
.build();
Response response = client.newCall(request).execute();
return response.code();
}
private static HttpURLConnection getUrlConnection(URL url, Context context, String username, String password) throws IOException, KeyManagementException, NoSuchAlgorithmException {
URLConnection urlConnection = url.openConnection();
// If https is used, use MemorizingTrustManager for certificate verification
if (urlConnection instanceof HttpsURLConnection) {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) urlConnection;
// set location of the keystore
MemorizingTrustManager.setKeyStoreFile("private", "sslkeys.bks");
// register MemorizingTrustManager for HTTPS
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, MemorizingTrustManager.getInstanceList(context),
new java.security.SecureRandom());
// enables TLSv1.1/1.2 for Jelly Bean Devices
TLSSocketFactory tlsSocketFactory = new TLSSocketFactory(sc);
httpsURLConnection.setSSLSocketFactory(tlsSocketFactory);
// disable redirects to reduce possible confusion
//httpsURLConnection.setFollowRedirects(false);
// disable hostname verification, when preference is set
// (this still shows a certification dialog, which requires user interaction!)
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
if(sp.getBoolean(SettingsActivity.CB_DISABLE_HOSTNAME_VERIFICATION_STRING, false))
httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
else
httpsURLConnection.setHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier());
}
if(username != null && password != null) {
urlConnection.setRequestProperty("Authorization", "Basic " + Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP));
}
return (HttpURLConnection) urlConnection;
}
public static int performCreateFeedRequest(String urlString, String username, String password, Context context, String feedUrl, long folderId) throws Exception {
HashMap<String,String> nameValuePairs = new HashMap<>();
nameValuePairs.put("url", feedUrl);
nameValuePairs.put("folderId", String.valueOf(folderId));
urlString += getUrlEncodedString(nameValuePairs);
URL url = new URL(API.validateURL(urlString));
HttpURLConnection urlConnection = getUrlConnection(url, context, username, password);
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(false);
urlConnection.setDoInput(true);
//urlConnection.setFollowRedirects(true);
urlConnection.setUseCaches(false);
urlConnection.setConnectTimeout(10000);
urlConnection.setReadTimeout(120000);//2min
urlConnection.setRequestProperty("Content-Type","application/json");
urlConnection.connect();
return urlConnection.getResponseCode();
}
@SuppressLint("DefaultLocale")
public static int performTagChangeRequest(String urlString, String username, String password, Context context, String content) throws Exception
public int performTagChangeRequest(String urlString, String content) throws Exception
{
URL url = new URL(API.validateURL(urlString));
HttpURLConnection urlConnection = getUrlConnection(url, context, username, password);
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("PUT");
urlConnection.setRequestProperty("Content-Type","application/json");
HttpUrl url = HttpUrl.parse(API.validateURL(urlString));
if(content != null) {
OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
out.write(content);
out.close();
}
Request request = new Request.Builder()
.url(url)
.put(RequestBody.create(JSON, content))
.build();
return urlConnection.getResponseCode();
Response response = client.newCall(request).execute();
return response.code();
}
}

View file

@ -106,15 +106,6 @@ public abstract class API {
return oc_root_path;
}
public String getUsername() {
return mPrefs.getString(SettingsActivity.EDT_USERNAME_STRING, null);
}
public String getPassword() {
return mPrefs.getString(SettingsActivity.EDT_PASSWORD_STRING, null);
}
public int[] GetFeeds(Context cont, API api) throws Exception {
return OwnCloudReaderMethods.GetFeeds(cont, api);
}

View file

@ -30,15 +30,8 @@ import de.luhmer.owncloudnewsreader.reader.AsyncTask_Reader;
import de.luhmer.owncloudnewsreader.reader.OnAsyncTaskCompletedListener;
public class AsyncTask_GetApiVersion extends AsyncTask_Reader {
private String username;
private String password;
public AsyncTask_GetApiVersion(final int task_id, final Context context, String username, String password, final OnAsyncTaskCompletedListener[] listener) {
public AsyncTask_GetApiVersion(final int task_id, final Context context, final OnAsyncTaskCompletedListener[] listener) {
super(task_id, context, listener);
this.username = username;
this.password = password;
}
@Override
@ -46,7 +39,7 @@ public class AsyncTask_GetApiVersion extends AsyncTask_Reader {
try {
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String oc_root_path = mPrefs.getString(SettingsActivity.EDT_OWNCLOUDROOTPATH_STRING, "");
return OwnCloudReaderMethods.GetVersionNumber(context, username, password, oc_root_path);
return OwnCloudReaderMethods.GetVersionNumber(context, oc_root_path);
} catch (Exception ex) {
return ex;
}

View file

@ -67,7 +67,7 @@ public class OwnCloudReaderMethods {
nVPairs.put("lastModified", String.valueOf(lastSync));
InputStream is = HttpJsonRequest.PerformJsonRequest(api.getItemUpdatedUrl(), nVPairs, api.getUsername(), api.getPassword(), cont);
InputStream is = HttpJsonRequest.getInstance().PerformJsonRequest(api.getItemUpdatedUrl(), nVPairs);
DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(cont);
try
@ -104,7 +104,7 @@ public class OwnCloudReaderMethods {
nVPairs.put("getRead", "false");
InputStream is = HttpJsonRequest.PerformJsonRequest(api.getItemUrl(), nVPairs, api.getUsername(), api.getPassword(), cont);
InputStream is = HttpJsonRequest.getInstance().PerformJsonRequest(api.getItemUrl(), nVPairs);
DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(cont);
try
@ -122,7 +122,7 @@ public class OwnCloudReaderMethods {
public static int GetFolderTags(Context cont, API api) throws Exception
{
InputStream is = HttpJsonRequest.PerformJsonRequest(api.getFolderUrl(), null, api.getUsername(), api.getPassword(), cont);
InputStream is = HttpJsonRequest.getInstance().PerformJsonRequest(api.getFolderUrl(), null);
DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(cont);
int[] result = new int[2];
try
@ -144,7 +144,7 @@ public class OwnCloudReaderMethods {
public static int[] GetFeeds(Context cont, API api) throws Exception
{
InputStream inputStream = HttpJsonRequest.PerformJsonRequest(api.getFeedUrl() , null, api.getUsername(), api.getPassword(), cont);
InputStream inputStream = HttpJsonRequest.getInstance().PerformJsonRequest(api.getFeedUrl() , null);
DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(cont);
int result[] = new int[2];
@ -387,7 +387,7 @@ public class OwnCloudReaderMethods {
}
try
{
int result = HttpJsonRequest.performTagChangeRequest(url, api.getUsername(), api.getPassword(), context, jsonIds);
int result = HttpJsonRequest.getInstance().performTagChangeRequest(url, jsonIds);
//if(result != -1 || result != 405)
return (result == 200);
}
@ -423,7 +423,7 @@ public class OwnCloudReaderMethods {
}
try
{
int result = HttpJsonRequest.performTagChangeRequest(url, api.getUsername(), api.getPassword(), context, null);
int result = HttpJsonRequest.getInstance().performTagChangeRequest(url, null);
return (result == 200);
}
catch (Exception ex)
@ -434,13 +434,13 @@ public class OwnCloudReaderMethods {
}
public static String GetVersionNumber(Context cont, String username, String password, String oc_root_path) throws Exception
public static String GetVersionNumber(Context cont, String oc_root_path) throws Exception
{
//Try APIv2
try {
String requestUrl = oc_root_path + OwnCloudConstants.ROOT_PATH_APIv2 + OwnCloudConstants.VERSION_PATH;
requestUrl = API.validateURL(requestUrl);
InputStream is = HttpJsonRequest.PerformJsonRequest(requestUrl, null, username, password, cont);
InputStream is = HttpJsonRequest.getInstance().PerformJsonRequest(requestUrl, null);
try {
GetVersion_v2 gv = new GetVersion_v2();
readJsonStreamSimple(is, gv);
@ -451,7 +451,7 @@ public class OwnCloudReaderMethods {
} catch(Exception ex) {//TODO GET HERE THE RIGHT EXCEPTION
String requestUrl = oc_root_path + OwnCloudConstants.ROOT_PATH_APIv1 + OwnCloudConstants.VERSION_PATH + OwnCloudConstants.JSON_FORMAT;
requestUrl = API.validateURL(requestUrl);
InputStream is = HttpJsonRequest.PerformJsonRequest(requestUrl, null, username, password, cont);
InputStream is = HttpJsonRequest.getInstance().PerformJsonRequest(requestUrl, null);
try {
GetVersion_v1 gv = new GetVersion_v1();
readJsonStreamSimple(is, gv);

View file

@ -68,9 +68,9 @@ public class OwnCloud_Reader {
public void Start_AsyncTask_GetVersion(int task_id,
Context context, OnAsyncTaskCompletedListener listener, String username, String password) {
Context context, OnAsyncTaskCompletedListener listener) {
setSyncRunning(true);
new AsyncTask_GetApiVersion(task_id, context, username, password, new OnAsyncTaskCompletedListener[] { AsyncTask_finished, listener }).execute();
new AsyncTask_GetApiVersion(task_id, context, new OnAsyncTaskCompletedListener[] { AsyncTask_finished, listener }).execute();
}
public boolean isSyncRunning() {

View file

@ -34,6 +34,8 @@ import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
import org.apache.commons.lang3.time.StopWatch;
import java.util.ArrayList;
import java.util.List;
@ -71,11 +73,8 @@ public class OwnCloudSyncService extends Service {
if(!isSyncRunning()) {
// Only check for API version once
if(_Reader.getApi() == null) {
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, OwnCloudSyncService.this, onAsyncTask_GetVersionFinished);
startedSync(SYNC_TYPES.SYNC_TYPE__GET_API);
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(OwnCloudSyncService.this);
String username = mPrefs.getString(SettingsActivity.EDT_USERNAME_STRING, "");
String password = mPrefs.getString(SettingsActivity.EDT_PASSWORD_STRING, "");
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, OwnCloudSyncService.this, onAsyncTask_GetVersionFinished, username, password);
} else {
_Reader.Start_AsyncTask_PerformItemStateChange(Constants.TaskID_PerformStateChange, OwnCloudSyncService.this, onAsyncTask_PerformTagExecute);
startedSync(SYNC_TYPES.SYNC_TYPE__ITEM_STATES);

View file

@ -49,10 +49,7 @@ public class SyncItemStateService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String username = mPrefs.getString(SettingsActivity.EDT_USERNAME_STRING, "");
String password = mPrefs.getString(SettingsActivity.EDT_PASSWORD_STRING, "");
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, this, onAsyncTask_GetVersionFinished, username, password);
_Reader.Start_AsyncTask_GetVersion(Constants.TaskID_GetVersion, this, onAsyncTask_GetVersionFinished);
}
OnAsyncTaskCompletedListener onAsyncTask_GetVersionFinished = new OnAsyncTaskCompletedListener() {