| /******************************************************************************* |
| * Copyright (c) 2011, 2014 Tasktop Technologies and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Tasktop Technologies - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.commons.repositories.http.core; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InterruptedIOException; |
| import java.net.InetAddress; |
| import java.net.InetSocketAddress; |
| import java.net.Proxy; |
| import java.net.URI; |
| import java.net.UnknownHostException; |
| import java.util.Locale; |
| |
| import org.apache.http.HttpEntity; |
| import org.apache.http.HttpHost; |
| import org.apache.http.HttpRequest; |
| import org.apache.http.HttpResponse; |
| import org.apache.http.auth.AuthScope; |
| import org.apache.http.auth.Credentials; |
| import org.apache.http.auth.NTCredentials; |
| import org.apache.http.auth.UsernamePasswordCredentials; |
| import org.apache.http.client.methods.HttpRequestBase; |
| import org.apache.http.client.methods.HttpUriRequest; |
| import org.apache.http.client.params.AuthPolicy; |
| import org.apache.http.client.params.ClientPNames; |
| import org.apache.http.client.params.CookiePolicy; |
| import org.apache.http.client.params.HttpClientParams; |
| import org.apache.http.conn.params.ConnRoutePNames; |
| import org.apache.http.conn.scheme.Scheme; |
| import org.apache.http.conn.scheme.SchemeRegistry; |
| import org.apache.http.conn.scheme.SchemeSocketFactory; |
| import org.apache.http.impl.EnglishReasonPhraseCatalog; |
| import org.apache.http.impl.client.AbstractHttpClient; |
| import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; |
| import org.apache.http.params.HttpConnectionParams; |
| import org.apache.http.params.HttpProtocolParams; |
| import org.apache.http.protocol.HttpContext; |
| import org.apache.http.util.EntityUtils; |
| import org.eclipse.core.net.proxy.IProxyData; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.mylyn.commons.core.CoreUtil; |
| import org.eclipse.mylyn.commons.core.StatusHandler; |
| import org.eclipse.mylyn.commons.core.net.AuthenticatedProxy; |
| import org.eclipse.mylyn.commons.core.net.NetUtil; |
| import org.eclipse.mylyn.commons.core.operations.CancellableOperationMonitorThread; |
| import org.eclipse.mylyn.commons.core.operations.ICancellableOperation; |
| import org.eclipse.mylyn.commons.core.operations.IOperationMonitor; |
| import org.eclipse.mylyn.commons.core.operations.OperationUtil; |
| import org.eclipse.mylyn.commons.repositories.core.RepositoryLocation; |
| import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationType; |
| import org.eclipse.mylyn.commons.repositories.core.auth.UserCredentials; |
| import org.eclipse.mylyn.internal.commons.repositories.http.core.IdleConnectionMonitorThread; |
| import org.eclipse.mylyn.internal.commons.repositories.http.core.PollingProtocolSocketFactory; |
| import org.eclipse.mylyn.internal.commons.repositories.http.core.PollingSslProtocolSocketFactory; |
| |
| /** |
| * @author Steffen Pingel |
| * @author Shawn Minto |
| * @author Christian Janz |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| */ |
| public class HttpUtil { |
| |
| static { |
| CoreUtil.initializeLoggingSettings(); |
| } |
| |
| @SuppressWarnings("unused") |
| private static final int BUFFER_SIZE = 4096; |
| |
| @SuppressWarnings("unused") |
| private static final long CLOSE_TIMEOUT = -1; |
| |
| /** |
| * @see IdleConnectionMonitorThread |
| */ |
| private static final int CONNECTION_TIMEOUT_INTERVAL = 1 * 30 * 1000; |
| |
| private static final int CONNNECT_TIMEOUT = 60 * 1000; |
| |
| private static final int HTTP_PORT = 80; |
| |
| private static final int HTTPS_PORT = 443; |
| |
| private static final int POLL_INTERVAL = 500; |
| |
| private static final int SOCKET_TIMEOUT = 3 * 60 * 1000; |
| |
| @SuppressWarnings("unused") |
| private static final int POLL_ATTEMPTS = SOCKET_TIMEOUT / POLL_INTERVAL; |
| |
| private static SchemeSocketFactory socketFactory = new PollingProtocolSocketFactory(); |
| |
| private static SchemeSocketFactory sslSocketFactory = new PollingSslProtocolSocketFactory(); |
| |
| static final String ID_PLUGIN = "org.eclipse.mylyn.commons.repositories.http"; //$NON-NLS-1$ |
| |
| private static ThreadSafeClientConnManager connectionManager; |
| |
| static final String CONTEXT_KEY_MONITOR_THREAD = CancellableOperationMonitorThread.class.getName(); |
| |
| public static void configureClient(AbstractHttpClient client, String userAgent) { |
| HttpClientParams.setCookiePolicy(client.getParams(), CookiePolicy.BEST_MATCH); |
| |
| if (userAgent != null) { |
| HttpProtocolParams.setUserAgent(client.getParams(), userAgent); |
| } |
| HttpProtocolParams.setUseExpectContinue(client.getParams(), true); |
| client.getParams().setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); |
| |
| HttpConnectionParams.setConnectionTimeout(client.getParams(), CONNNECT_TIMEOUT); |
| HttpConnectionParams.setSoTimeout(client.getParams(), SOCKET_TIMEOUT); |
| |
| //AuthParams.setCredentialCharset(client.getParams(), "UTF-8"); |
| } |
| |
| public static void configureAuthentication(AbstractHttpClient client, RepositoryLocation location) { |
| UserCredentials credentials = location.getCredentials(AuthenticationType.HTTP); |
| if (credentials != null) { |
| configureAuthentication(client, location, credentials); |
| } |
| } |
| |
| public static void configureAuthentication(AbstractHttpClient client, RepositoryLocation location, |
| UserCredentials credentials) { |
| Assert.isNotNull(client); |
| Assert.isNotNull(location); |
| Assert.isNotNull(credentials); |
| String url = location.getUrl(); |
| Assert.isNotNull(url, "The location url must not be null"); //$NON-NLS-1$ |
| |
| String host = NetUtil.getHost(url); |
| int port = NetUtil.getPort(url); |
| |
| NTCredentials ntlmCredentials = getNtCredentials(credentials, ""); //$NON-NLS-1$ |
| if (ntlmCredentials != null) { |
| AuthScope authScopeNtlm = new AuthScope(host, port, AuthScope.ANY_REALM, AuthPolicy.NTLM); |
| client.getCredentialsProvider().setCredentials(authScopeNtlm, ntlmCredentials); |
| } |
| |
| UsernamePasswordCredentials usernamePasswordCredentials = getUserNamePasswordCredentials(credentials); |
| AuthScope authScopeAny = new AuthScope(host, port, AuthScope.ANY_REALM); |
| client.getCredentialsProvider().setCredentials(authScopeAny, usernamePasswordCredentials); |
| } |
| |
| public static HttpHost createHost(HttpRequestBase method) { |
| URI uri = method.getURI(); |
| return new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); |
| } |
| |
| public static HttpResponse execute(final AbstractHttpClient client, final HttpContext context, |
| final HttpRequestBase method, IProgressMonitor monitor) throws IOException { |
| return execute(client, createHost(method), context, method, monitor); |
| } |
| |
| public static HttpResponse execute(final AbstractHttpClient client, final HttpHost host, final HttpContext context, |
| final HttpRequestBase method, final IProgressMonitor progress) throws IOException { |
| Assert.isNotNull(client); |
| Assert.isNotNull(method); |
| |
| final IOperationMonitor monitor = OperationUtil.convert(progress); |
| ICancellableOperation operation = new ICancellableOperation() { |
| @Override |
| public void abort() { |
| method.abort(); |
| } |
| |
| @Override |
| public boolean isCanceled() { |
| return monitor.isCanceled(); |
| } |
| }; |
| |
| CancellableOperationMonitorThread thread = null; |
| if (context != null) { |
| thread = (CancellableOperationMonitorThread) context.getAttribute(CONTEXT_KEY_MONITOR_THREAD); |
| } |
| if (thread != null) { |
| thread.addOperation(operation); |
| } |
| try { |
| return client.execute(host, method, context); |
| } catch (InterruptedIOException e) { |
| if (monitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| throw e; |
| } finally { |
| if (thread != null) { |
| thread.removeOperation(operation); |
| } |
| } |
| } |
| |
| public static NTCredentials getNtCredentials(UserCredentials credentials, String workstation) { |
| String username = credentials.getUserName(); |
| int i = username.indexOf("\\"); //$NON-NLS-1$ |
| if (i > 0 && i < username.length() - 1) { |
| // try { |
| // InetAddress localHost = InetAddress.getLocalHost(); |
| // if (localHost != null) { |
| // hostName = localHost.getHostName(); |
| // } |
| // } catch (UnknownHostException e) { |
| // StatusHandler.log(new Status(IStatus.ERROR, ID_PLUGIN, |
| // "Unable to get hostname. Defaulting to servers host.", e)); |
| // } |
| return new NTCredentials(username.substring(i + 1), credentials.getPassword(), workstation, |
| username.substring(0, i)); |
| } |
| return null; |
| } |
| |
| public static UsernamePasswordCredentials getUserNamePasswordCredentials(UserCredentials credentials) { |
| return new UsernamePasswordCredentials(credentials.getUserName(), credentials.getPassword()); |
| } |
| |
| public static InputStream getResponseBodyAsStream(HttpEntity entity, IProgressMonitor monitor) throws IOException { |
| monitor = OperationUtil.convert(monitor); |
| return entity.getContent(); |
| // return new PollingInputStream(new TimeoutInputStream(entity.getContent(), BUFFER_SIZE, POLL_INTERVAL, |
| // CLOSE_TIMEOUT), POLL_ATTEMPTS, monitor); |
| } |
| |
| public static SchemeRegistry getSchemeRegistry() { |
| SchemeRegistry schemeRegistry = new SchemeRegistry(); |
| schemeRegistry.register(new Scheme("http", HTTP_PORT, socketFactory)); //$NON-NLS-1$ |
| schemeRegistry.register(new Scheme("https", HTTPS_PORT, sslSocketFactory)); //$NON-NLS-1$ |
| return schemeRegistry; |
| } |
| |
| public static void configureProxy(AbstractHttpClient client, RepositoryLocation location) { |
| Assert.isNotNull(client); |
| Assert.isNotNull(location); |
| String url = location.getUrl(); |
| Assert.isNotNull(url, "The location url must not be null"); //$NON-NLS-1$ |
| |
| String host = NetUtil.getHost(url); |
| Proxy proxy; |
| if (NetUtil.isUrlHttps(url)) { |
| proxy = location.getProxyForHost(host, IProxyData.HTTPS_PROXY_TYPE); |
| } else { |
| proxy = location.getProxyForHost(host, IProxyData.HTTP_PROXY_TYPE); |
| } |
| |
| if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) { |
| InetSocketAddress address = (InetSocketAddress) proxy.address(); |
| |
| client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, |
| new HttpHost(address.getHostName(), address.getPort())); |
| |
| if (proxy instanceof AuthenticatedProxy) { |
| AuthenticatedProxy authProxy = (AuthenticatedProxy) proxy; |
| Credentials credentials = getCredentials(authProxy.getUserName(), authProxy.getPassword(), |
| address.getAddress(), false); |
| if (credentials instanceof NTCredentials) { |
| AuthScope proxyAuthScopeNTLM = new AuthScope(address.getHostName(), address.getPort(), |
| AuthScope.ANY_REALM, AuthPolicy.NTLM); |
| client.getCredentialsProvider().setCredentials(proxyAuthScopeNTLM, credentials); |
| |
| AuthScope proxyAuthScopeAny = new AuthScope(address.getHostName(), address.getPort(), |
| AuthScope.ANY_REALM); |
| Credentials usernamePasswordCredentials = getCredentials(authProxy.getUserName(), |
| authProxy.getPassword(), address.getAddress(), true); |
| client.getCredentialsProvider().setCredentials(proxyAuthScopeAny, usernamePasswordCredentials); |
| |
| } else { |
| AuthScope proxyAuthScope = new AuthScope(address.getHostName(), address.getPort(), |
| AuthScope.ANY_REALM); |
| client.getCredentialsProvider().setCredentials(proxyAuthScope, credentials); |
| } |
| } |
| } else { |
| client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, null); |
| } |
| } |
| |
| static Credentials getCredentials(final String username, final String password, final InetAddress address, |
| boolean forceUserNamePassword) { |
| int i = username.indexOf("\\"); //$NON-NLS-1$ |
| if (i > 0 && i < username.length() - 1 && address != null && !forceUserNamePassword) { |
| String hostName = address.getHostName(); |
| try { |
| InetAddress localHost = InetAddress.getLocalHost(); |
| if (localHost != null) { |
| hostName = localHost.getHostName(); |
| } |
| } catch (UnknownHostException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, ID_PLUGIN, |
| "Unable to get hostname. Defaulting to servers host.", e)); //$NON-NLS-1$ |
| } |
| if (hostName == null) { |
| hostName = address.getHostName(); |
| } |
| return new NTCredentials(username.substring(i + 1), password, hostName, username.substring(0, i)); |
| } else { |
| return new UsernamePasswordCredentials(username, password); |
| } |
| } |
| |
| public static synchronized ThreadSafeClientConnManager getConnectionManager() { |
| if (connectionManager == null) { |
| connectionManager = new ThreadSafeClientConnManager(HttpUtil.getSchemeRegistry()); |
| if (CoreUtil.TEST_MODE) { |
| connectionManager.setDefaultMaxPerRoute(2); |
| } else { |
| connectionManager.setDefaultMaxPerRoute(NetUtil.getMaxHttpConnectionsPerHost()); |
| connectionManager.setMaxTotal(NetUtil.getMaxHttpConnections()); |
| } |
| |
| IdleConnectionMonitorThread thread = new IdleConnectionMonitorThread(CONNECTION_TIMEOUT_INTERVAL); |
| thread.setTimeout(CONNNECT_TIMEOUT); |
| thread.addConnectionManager(connectionManager); |
| thread.start(); |
| } |
| return connectionManager; |
| } |
| |
| public static String getStatusText(int statusCode) { |
| return EnglishReasonPhraseCatalog.INSTANCE.getReason(statusCode, Locale.getDefault()); |
| } |
| |
| public static void release(HttpRequest request, HttpResponse response, IProgressMonitor monitor) { |
| Assert.isNotNull(request); |
| Assert.isNotNull(response); |
| if (monitor != null && monitor.isCanceled() && request instanceof HttpUriRequest) { |
| // force a connection close on cancel to avoid blocking to do reading the remainder of the response |
| try { |
| ((HttpUriRequest) request).abort(); |
| } catch (UnsupportedOperationException e) { |
| // fall back to standard close |
| consume(request, response); |
| } |
| } else { |
| consume(request, response); |
| } |
| } |
| |
| private static void consume(HttpRequest request, HttpResponse response) { |
| try { |
| EntityUtils.consume(response.getEntity()); |
| } catch (IOException e) { |
| // if construction of the stream fails the connection has to be aborted to be released |
| try { |
| ((HttpUriRequest) request).abort(); |
| } catch (UnsupportedOperationException e2) { |
| } |
| } catch (NullPointerException e2) { |
| // XXX work-around for bug 368830 |
| } |
| } |
| |
| } |