diff options
Diffstat (limited to 'src/plugins/common/src/com/motorola/studio/android/common/utilities/HttpUtils.java')
-rw-r--r-- | src/plugins/common/src/com/motorola/studio/android/common/utilities/HttpUtils.java | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/plugins/common/src/com/motorola/studio/android/common/utilities/HttpUtils.java b/src/plugins/common/src/com/motorola/studio/android/common/utilities/HttpUtils.java new file mode 100644 index 0000000..8fb7238 --- /dev/null +++ b/src/plugins/common/src/com/motorola/studio/android/common/utilities/HttpUtils.java @@ -0,0 +1,300 @@ +/* +* Copyright (C) 2012 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.motorola.studio.android.common.utilities; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Authenticator; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.auth.AuthState; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.params.HttpClientParams; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.eclipse.core.internal.net.ProxyManager; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.ui.internal.net.auth.NetAuthenticator; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorola.studio.android.common.utilities.i18n.UtilitiesNLS; +import com.motorola.studio.android.common.utilities.ui.LoginPasswordDialogCreator; + +/** + * Class for opening an input stream with the given URL. + */ +@SuppressWarnings("restriction") +public class HttpUtils +{ + /** + * 1 second if the unit is milliseconds. + */ + private static final int ONE_SECOND = 1000; + + // map of credentials authentication so the user is not repeatedly asked for them + private static final Map<String, Credentials> authenticationRealmCache = + new HashMap<String, Credentials>(); + + private GetMethod getMethod; + + /** + * Retrieves an open InputStream with the contents of the file pointed by the given url. + * + * @param url The address from where to retrieve the InputStream + * @param monitor The monitor to progress while accessing the file + * + * @return The open InputStream object, or <code>null</code> if no file was found + * + * @throws IOException if some error occurs with the network communication + */ + public InputStream getInputStreamForUrl(String url, IProgressMonitor monitor) + throws IOException + { + return getInputStreamForUrl(url, monitor, true); + } + + private InputStream getInputStreamForUrl(String url, IProgressMonitor monitor, + boolean returnStream) throws IOException + { + SubMonitor subMonitor = SubMonitor.convert(monitor); + + subMonitor.beginTask(UtilitiesNLS.HttpUtils_MonitorTask_PreparingConnection, 300); + + StudioLogger.debug(HttpUtils.class, "Verifying proxy usage for opening http connection"); //$NON-NLS-1$ + + // Try to retrieve proxy configuration to use if necessary + IProxyService proxyService = ProxyManager.getProxyManager(); + IProxyData proxyData = null; + if (proxyService.isProxiesEnabled() || proxyService.isSystemProxiesEnabled()) + { + Authenticator.setDefault(new NetAuthenticator()); + if (url.startsWith("https")) + { + proxyData = proxyService.getProxyData(IProxyData.HTTPS_PROXY_TYPE); + StudioLogger.debug(HttpUtils.class, "Using https proxy"); //$NON-NLS-1$ + } + else if (url.startsWith("http")) + { + proxyData = proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE); + StudioLogger.debug(HttpUtils.class, "Using http proxy"); //$NON-NLS-1$ + } + else + { + StudioLogger.debug(HttpUtils.class, "Not using any proxy"); //$NON-NLS-1$ + } + } + + // Creates the http client and the method to be executed + HttpClient client = null; + client = new HttpClient(); + + // If there is proxy data, work with it + if (proxyData != null) + { + if (proxyData.getHost() != null) + { + // Sets proxy host and port, if any + client.getHostConfiguration().setProxy(proxyData.getHost(), proxyData.getPort()); + } + + if ((proxyData.getUserId() != null) && (proxyData.getUserId().trim().length() > 0)) + { + // Sets proxy user and password, if any + Credentials cred = + new UsernamePasswordCredentials(proxyData.getUserId(), + proxyData.getPassword() == null ? "" : proxyData.getPassword()); //$NON-NLS-1$ + client.getState().setProxyCredentials(AuthScope.ANY, cred); + } + } + + InputStream streamForUrl = null; + getMethod = new GetMethod(url); + getMethod.setFollowRedirects(true); + + // set a 30 seconds timeout + HttpMethodParams params = getMethod.getParams(); + params.setSoTimeout(15 * ONE_SECOND); + getMethod.setParams(params); + + boolean trying = true; + Credentials credentials = null; + subMonitor.worked(100); + subMonitor.setTaskName(UtilitiesNLS.HttpUtils_MonitorTask_ContactingSite); + do + { + StudioLogger.info(HttpUtils.class, "Attempting to make a connection"); //$NON-NLS-1$ + + // retry to connect to the site once, also set the timeout for 5 seconds + HttpClientParams clientParams = client.getParams(); + clientParams.setIntParameter(HttpClientParams.MAX_REDIRECTS, 1); + clientParams.setSoTimeout(5 * ONE_SECOND); + client.setParams(clientParams); + + client.executeMethod(getMethod); + if (subMonitor.isCanceled()) + { + break; + } + else + { + AuthState authorizationState = getMethod.getHostAuthState(); + String authenticationRealm = authorizationState.getRealm(); + + if (getMethod.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) + { + StudioLogger.debug(HttpUtils.class, + "Client requested authentication; retrieving credentials"); //$NON-NLS-1$ + + credentials = authenticationRealmCache.get(authenticationRealm); + + if (credentials == null) + { + StudioLogger.debug(HttpUtils.class, + "Credentials not found; prompting user for login/password"); //$NON-NLS-1$ + + subMonitor + .setTaskName(UtilitiesNLS.HttpUtils_MonitorTask_WaitingAuthentication); + + LoginPasswordDialogCreator dialogCreator = + new LoginPasswordDialogCreator(url); + if (dialogCreator.openLoginPasswordDialog() == LoginPasswordDialogCreator.OK) + { + + credentials = + new UsernamePasswordCredentials(dialogCreator.getTypedLogin(), + dialogCreator.getTypedPassword()); + } + else + { + // cancel pressed; stop trying + trying = false; + + // set the monitor canceled to be able to stop process + subMonitor.setCanceled(true); + } + + } + + if (credentials != null) + { + AuthScope scope = new AuthScope(null, -1, authenticationRealm); + client.getState().setCredentials(scope, credentials); + } + + subMonitor.worked(100); + } + else if (getMethod.getStatusCode() == HttpStatus.SC_OK) + { + StudioLogger.debug(HttpUtils.class, "Http connection suceeded"); //$NON-NLS-1$ + + subMonitor + .setTaskName(UtilitiesNLS.HttpUtils_MonitorTask_RetrievingSiteContent); + if ((authenticationRealm != null) && (credentials != null)) + { + authenticationRealmCache.put(authenticationRealm, credentials); + } + else + { + // no authentication was necessary, just work the monitor + subMonitor.worked(100); + } + + StudioLogger.info(HttpUtils.class, "Retrieving site content"); //$NON-NLS-1$ + + // if the stream should not be returned (ex: only testing the connection is + // possible), then null will be returned + if (returnStream) + { + streamForUrl = getMethod.getResponseBodyAsStream(); + } + + // succeeded; stop trying + trying = false; + + subMonitor.worked(100); + } + else + { + // unhandled return status code + trying = false; + + subMonitor.worked(200); + } + } + } + while (trying); + + subMonitor.done(); + + return streamForUrl; + } + + /** + * Check if a connection with the given URL can be established. + * + * @param url The URL to test the connection. + * + * @return <code>true</code> if the connection can be established; <code>false</code> otherwise + */ + public boolean isConnectionOk(String url) + { + try + { + getInputStreamForUrl(url, null, false); + // no need to release connection since the stream has not been retrieved + // if the code above does not throw any exception, the connection is fine + return true; + } + catch (Exception e) + { + return false; + } + } + + /** + * Release the http connection after users finished reading the InputStream + * provided by the {@link #getInputStreamForUrl(String, IProgressMonitor)} + * method. + */ + public void releaseConnection() + { + if (getMethod != null) + { + Thread t = new Thread() + { + /* (non-Javadoc) + * @see java.lang.Thread#run() + */ + @Override + public void run() + { + getMethod.releaseConnection(); + } + }; + t.start(); + + } + } +} |