Fixed crash by URL with whitespaces in login page; reviewed error handling and user...
[pub/Android/ownCloud.git] / src / com / owncloud / android / authenticator / ConnectionCheckerRunnable.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.authenticator;
20
21 import java.io.IOException;
22 import java.net.ConnectException;
23 import java.net.MalformedURLException;
24 import java.net.SocketException;
25 import java.net.SocketTimeoutException;
26 import java.net.URI;
27 import java.net.URL;
28 import java.net.UnknownHostException;
29
30 import javax.net.ssl.SSLException;
31 import javax.net.ssl.SSLHandshakeException;
32 import javax.net.ssl.SSLPeerUnverifiedException;
33
34 import org.apache.commons.httpclient.HttpException;
35 import org.apache.commons.httpclient.HttpStatus;
36 import org.apache.commons.httpclient.methods.GetMethod;
37 import org.json.JSONException;
38 import org.json.JSONObject;
39
40 import com.owncloud.android.AccountUtils;
41 import com.owncloud.android.authenticator.OnConnectCheckListener.ResultType;
42 import com.owncloud.android.utils.OwnCloudVersion;
43
44 import eu.alefzero.webdav.WebdavClient;
45 import android.content.Context;
46 import android.net.ConnectivityManager;
47 import android.net.Uri;
48 import android.os.Handler;
49 import android.util.Log;
50
51 public class ConnectionCheckerRunnable implements Runnable {
52
53 /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs. */
54 public static final int TRY_CONNECTION_TIMEOUT = 5000;
55
56 private static final String TAG = "ConnectionCheckerRunnable";
57 private OnConnectCheckListener mListener;
58 private String mUrl;
59 private Handler mHandler;
60 private ResultType mLatestResult;
61 private Context mContext;
62 private OwnCloudVersion mOCVersion;
63
64 public void setListener(OnConnectCheckListener listener, Handler handler) {
65 mListener = listener;
66 mHandler = handler;
67 }
68
69 public ConnectionCheckerRunnable(String url, Context context) {
70 mListener = null;
71 mHandler = null;
72 mUrl = url;
73 mContext = context;
74 mOCVersion = null;
75 }
76
77 @Override
78 public void run() {
79
80 if (!isOnline()) {
81 postResult(ResultType.NO_NETWORK_CONNECTION);
82 return;
83 }
84 if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
85 mLatestResult = (mUrl.startsWith("https://"))? ResultType.OK_SSL : ResultType.OK_NO_SSL;
86 tryConnection(mUrl + AccountUtils.STATUS_PATH);
87 postResult(mLatestResult);
88 } else {
89 if (tryConnection("https://" + mUrl + AccountUtils.STATUS_PATH)) {
90 postResult(ResultType.OK_SSL);
91 return;
92 }
93 Log.d(TAG,
94 "establishing secure connection failed, trying non secure connection");
95
96 if (tryConnection("http://" + mUrl + AccountUtils.STATUS_PATH)) {
97 postResult(ResultType.OK_NO_SSL);
98 return;
99 }
100 postResult(mLatestResult);
101 }
102 }
103
104 public OwnCloudVersion getDiscoveredVersion() {
105 return mOCVersion;
106 }
107
108 private boolean tryConnection(String urlSt) {
109 boolean retval = false;
110 try {
111 WebdavClient wc = new WebdavClient();
112 wc.allowSelfsignedCertificates();
113 URL url = new URL(urlSt); // better than android.net.Uri in this case; provides URL validation
114 GetMethod get = new GetMethod(url.toString());
115 int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT);
116 switch (status) {
117 case HttpStatus.SC_OK: {
118 String response = get.getResponseBodyAsString();
119 JSONObject json = new JSONObject(response);
120 if (!json.getBoolean("installed")) {
121 mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED;
122 break;
123 }
124 mOCVersion = new OwnCloudVersion(json.getString("version"));
125 if (!mOCVersion.isVersionValid()) {
126 mLatestResult = ResultType.BAD_OC_VERSION;
127 break;
128 }
129 retval = true;
130 break;
131 }
132 case HttpStatus.SC_NOT_FOUND:
133 mLatestResult = ResultType.FILE_NOT_FOUND;
134 break;
135 case HttpStatus.SC_INTERNAL_SERVER_ERROR:
136 mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED;
137 break;
138 default:
139 mLatestResult = ResultType.UNKNOWN_ERROR;
140 Log.e(TAG, "Not handled status received from server: " + status);
141 }
142
143 } catch (JSONException e) {
144 mLatestResult = ResultType.INSTANCE_NOT_CONFIGURED;
145 Log.e(TAG, "JSON exception while trying connection (instance not configured) ", e);
146
147 } catch (SocketException e) {
148 mLatestResult = ResultType.WRONG_CONNECTION;
149 Log.e(TAG, "Socket exception while trying connection", e);
150
151 } catch (SocketTimeoutException e) {
152 mLatestResult = ResultType.TIMEOUT;
153 Log.e(TAG, "Socket timeout exception while trying connection", e);
154
155 } catch (MalformedURLException e) {
156 mLatestResult = ResultType.INCORRECT_ADDRESS;
157 Log.e(TAG, "Connect exception while trying connection", e);
158
159 } catch (UnknownHostException e) {
160 mLatestResult = ResultType.HOST_NOT_AVAILABLE;
161 Log.e(TAG, "Unknown host exception while trying connection", e);
162
163 } catch (SSLPeerUnverifiedException e) { // specially meaningful SSLException
164 mLatestResult = ResultType.SSL_UNVERIFIED_SERVER;
165 Log.e(TAG, "SSL Peer Unverified exception while trying connection", e);
166
167 } catch (SSLException e) {
168 mLatestResult = ResultType.SSL_INIT_ERROR;
169 Log.e(TAG, "SSL exception while trying connection", e);
170
171 } catch (HttpException e) { // specific exceptions from org.apache.commons.httpclient
172 mLatestResult = ResultType.UNKNOWN_ERROR;
173 Log.e(TAG, "HTTP exception while trying connection", e);
174
175 } catch (IOException e) { // UnkownsServiceException, and any other weird I/O Exception that could occur
176 mLatestResult = ResultType.UNKNOWN_ERROR;
177 Log.e(TAG, "I/O exception while trying connection", e);
178
179 } catch (Exception e) {
180 mLatestResult = ResultType.UNKNOWN_ERROR;
181 Log.e(TAG, "Unexpected exception while trying connection", e);
182 }
183
184 return retval;
185 }
186
187 private boolean isOnline() {
188 ConnectivityManager cm = (ConnectivityManager) mContext
189 .getSystemService(Context.CONNECTIVITY_SERVICE);
190 return cm != null && cm.getActiveNetworkInfo() != null
191 && cm.getActiveNetworkInfo().isConnectedOrConnecting();
192 }
193
194 private void postResult(final ResultType result) {
195 if (mHandler != null && mListener != null) {
196 mHandler.post(new Runnable() {
197 @Override
198 public void run() {
199 mListener.onConnectionCheckResult(result);
200 }
201 });
202 }
203 }
204
205 }