package com.zulip.android.networking; import android.os.AsyncTask; import android.util.Base64; import android.util.Log; import com.zulip.android.R; import com.zulip.android.ZulipApp; import com.zulip.android.util.ZLog; import org.apache.commons.lang.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * Simplified HTTP request API * Uses the {@link OkHttpClient} for requests. */ public class HTTPRequest { volatile boolean aborting = false; private ZulipApp app; private HashMap<String, String> properties; private OkHttpClient okHttpClient; private Response response = null; private String method, path; private Object synchronization = new Object(); public HTTPRequest(ZulipApp app) { properties = new HashMap<>(); this.app = app; okHttpClient = new OkHttpClient.Builder().readTimeout(60, TimeUnit.SECONDS).build(); } public void setMethodAndUrl(String method, String URL) { this.method = method; this.path = URL; } public void setProperty(String key, String value) { properties.put((key == null) ? "" : key, (value == null) ? "" : value); } void clearProperties() { properties.clear(); } void abort() { aborting = true; synchronized (synchronization) { if (response != null) { final Response finalResponse = response; response = null; (new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { try { finalResponse.body().close(); } catch (IllegalStateException e) { //fail silently } return null; } }).execute(); } } } public Response execute() throws IOException { if (method == null) throw new IOException(app.getString(R.string.method_null)); Request.Builder requestBuilder = new Request.Builder(); String url = app.getServerURI() + path; requestBuilder.addHeader("client", "Android"); requestBuilder.addHeader("User-Agent", app.getUserAgent()); switch (method) { case "GET": requestBuilder.url(generateURL(url, properties)).get(); break; case "DELETE": FormBody.Builder formDeleteBody = new FormBody.Builder(); for (Map.Entry<String, String> map : properties.entrySet()) { formDeleteBody.add(map.getKey(), map.getValue()); } requestBuilder.url(url).delete(formDeleteBody.build()); break; case "POST": FormBody.Builder formBody = new FormBody.Builder(); for (Map.Entry<String, String> map : properties.entrySet()) { formBody.add(map.getKey(), map.getValue()); } requestBuilder.url(url).post(formBody.build()); break; case "PUT": FormBody.Builder builder = new FormBody.Builder(); for (Map.Entry<String, String> map : properties.entrySet()) { builder.add(map.getKey(), map.getValue()); } requestBuilder.url(url).put(builder.build()); break; default: throw new IOException(app.getString(R.string.method_error)); } if (this.app.getApiKey() != null) { String authstr = this.app.getEmail() + ":" + this.app.getApiKey(); requestBuilder.addHeader("Authorization", "Basic " + Base64.encodeToString(authstr.getBytes(), Base64.NO_WRAP)); } Request request = requestBuilder.build(); Log.i("OkHTTP.request", method + " " + request.url().toString()); response = okHttpClient.newCall(request).execute(); return response; } private String generateURL(String url, HashMap<String, String> properties) { if (properties.isEmpty()) return url; String encodedUrl = url + "?"; for (Map.Entry<String, String> map : properties.entrySet()) { try { encodedUrl += URLEncoder.encode(map.getKey(), ("utf-8")) + "=" + URLEncoder.encode(map.getValue(), "utf-8") + "&"; } catch (UnsupportedEncodingException e) { ZLog.logException(e); } } StringUtils.removeEnd(encodedUrl, "&"); return encodedUrl; } }