package org.fox.ttrss; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.scheme.Scheme; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.fox.ttrss.util.EasySSLSocketFactory; import android.content.Context; import android.content.SharedPreferences; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.util.Log; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; public class ApiRequest extends AsyncTask, Integer, JsonElement> { private final String TAG = this.getClass().getSimpleName(); public enum ApiError { NO_ERROR, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_OTHER_ERROR, SSL_REJECTED, PARSE_ERROR, IO_ERROR, OTHER_ERROR, API_DISABLED, API_UNKNOWN, LOGIN_FAILED, INVALID_URL, INCORRECT_USAGE }; public static final int API_STATUS_OK = 0; public static final int API_STATUS_ERR = 1; private String m_api; private boolean m_trustAny = false; private boolean m_transportDebugging = false; protected int m_httpStatusCode = 0; protected int m_apiStatusCode = 0; protected Context m_context; private SharedPreferences m_prefs; protected ApiError m_lastError; public ApiRequest(Context context) { m_context = context; m_prefs = PreferenceManager.getDefaultSharedPreferences(m_context); m_api = m_prefs.getString("ttrss_url", null).trim(); m_trustAny = m_prefs.getBoolean("ssl_trust_any", false); m_transportDebugging = m_prefs.getBoolean("transport_debugging", false); m_lastError = ApiError.NO_ERROR; } protected int getErrorMessage() { switch (m_lastError) { case NO_ERROR: return R.string.error_unknown; case HTTP_UNAUTHORIZED: return R.string.error_http_unauthorized; case HTTP_FORBIDDEN: return R.string.error_http_forbidden; case HTTP_NOT_FOUND: return R.string.error_http_not_found; case HTTP_SERVER_ERROR: return R.string.error_http_server_error; case HTTP_OTHER_ERROR: return R.string.error_http_other_error; case SSL_REJECTED: return R.string.error_ssl_rejected; case PARSE_ERROR: return R.string.error_parse_error; case IO_ERROR: return R.string.error_io_error; case OTHER_ERROR: return R.string.error_other_error; case API_DISABLED: return R.string.error_api_disabled; case API_UNKNOWN: return R.string.error_api_unknown; case LOGIN_FAILED: return R.string.error_login_failed; case INVALID_URL: return R.string.error_invalid_api_url; case INCORRECT_USAGE: return R.string.error_api_incorrect_usage; default: Log.d(TAG, "getErrorMessage: unknown error code=" + m_lastError); return R.string.error_unknown; } } @Override protected JsonElement doInBackground(HashMap... params) { Gson gson = new Gson(); String requestStr = gson.toJson(new HashMap(params[0])); if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api); AndroidHttpClient client = AndroidHttpClient.newInstance("Tiny Tiny RSS"); if (m_trustAny) { client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", new EasySSLSocketFactory(), 443)); } try { HttpPost httpPost; try { httpPost = new HttpPost(m_api + "/api/"); } catch (IllegalArgumentException e) { m_lastError = ApiError.INVALID_URL; e.printStackTrace(); client.close(); return null; } catch (Exception e) { m_lastError = ApiError.OTHER_ERROR; e.printStackTrace(); client.close(); return null; } HttpContext context = null; String httpLogin = m_prefs.getString("http_login", "").trim(); String httpPassword = m_prefs.getString("http_password", "").trim(); if (httpLogin.length() > 0) { if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication."); URL targetUrl; try { targetUrl = new URL(m_api); } catch (MalformedURLException e) { m_lastError = ApiError.INVALID_URL; e.printStackTrace(); client.close(); return null; } HttpHost targetHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol()); CredentialsProvider cp = new BasicCredentialsProvider(); context = new BasicHttpContext(); cp.setCredentials( new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(httpLogin, httpPassword)); context.setAttribute(ClientContext.CREDS_PROVIDER, cp); } httpPost.setEntity(new StringEntity(requestStr, "utf-8")); HttpResponse execute = client.execute(httpPost, context); m_httpStatusCode = execute.getStatusLine().getStatusCode(); switch (m_httpStatusCode) { case 200: InputStream content = execute.getEntity().getContent(); BufferedReader buffer = new BufferedReader( new InputStreamReader(content), 8192); String s = ""; String response = ""; while ((s = buffer.readLine()) != null) { response += s; } if (m_transportDebugging) Log.d(TAG, "<<< " + response); JsonParser parser = new JsonParser(); JsonElement result = parser.parse(response); JsonObject resultObj = result.getAsJsonObject(); m_apiStatusCode = resultObj.get("status").getAsInt(); client.close(); switch (m_apiStatusCode) { case API_STATUS_OK: return result.getAsJsonObject().get("content"); case API_STATUS_ERR: JsonObject contentObj = resultObj.get("content").getAsJsonObject(); String error = contentObj.get("error").getAsString(); if (error.equals("LOGIN_ERROR")) { m_lastError = ApiError.LOGIN_FAILED; } else if (error.equals("API_DISABLED")) { m_lastError = ApiError.API_DISABLED; } else if (error.equals("NOT_LOGGED_IN")) { m_lastError = ApiError.LOGIN_FAILED; } else if (error.equals("INCORRECT_USAGE")) { m_lastError = ApiError.INCORRECT_USAGE; } else { Log.d(TAG, "Unknown API error: " + error); m_lastError = ApiError.API_UNKNOWN; } } return null; case 401: m_lastError = ApiError.HTTP_UNAUTHORIZED; break; case 403: m_lastError = ApiError.HTTP_FORBIDDEN; break; case 404: m_lastError = ApiError.HTTP_NOT_FOUND; break; case 500: m_lastError = ApiError.HTTP_SERVER_ERROR; break; default: m_lastError = ApiError.HTTP_OTHER_ERROR; break; } client.close(); return null; } catch (javax.net.ssl.SSLPeerUnverifiedException e) { m_lastError = ApiError.SSL_REJECTED; e.printStackTrace(); } catch (IOException e) { m_lastError = ApiError.IO_ERROR; e.printStackTrace(); } catch (com.google.gson.JsonSyntaxException e) { m_lastError = ApiError.PARSE_ERROR; e.printStackTrace(); } catch (Exception e) { m_lastError = ApiError.OTHER_ERROR; e.printStackTrace(); } client.close(); return null; } }