blob: 406344b3ee6f1fa053ef4880f87b0583924a7c30 [file] [log] [blame]
/****************************************************************************
* Copyright (c) 2008 Composent, Inc. 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:
* Composent, Inc. - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.provider.filetransfer.browse;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.net.proxy.IProxyService;
import org.eclipse.ecf.core.security.*;
import org.eclipse.ecf.core.util.Proxy;
import org.eclipse.ecf.core.util.ProxyAddress;
import org.eclipse.ecf.filetransfer.IRemoteFile;
import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener;
import org.eclipse.ecf.filetransfer.identity.IFileID;
import org.eclipse.ecf.internal.provider.filetransfer.*;
import org.eclipse.ecf.provider.filetransfer.util.JREProxyHelper;
/**
*
*/
public class URLFileSystemBrowser extends AbstractFileSystemBrowser {
private static final String USERNAME_PREFIX = Messages.UrlConnectionRetrieveFileTransfer_USERNAME_PROMPT;
private static final String JRE_CONNECT_TIMEOUT_PROPERTY = "sun.net.client.defaultConnectTimeout"; //$NON-NLS-1$
private static final String DEFAULT_CONNECT_TIMEOUT = "30000"; //$NON-NLS-1$
private static final String JRE_READ_TIMEOUT_PROPERTY = "sun.net.client.defaultReadTimeout"; //$NON-NLS-1$
private static final String DEFAULT_READ_TIMEOUT = "30000"; //$NON-NLS-1$
URL directoryOrFile;
IConnectContext connectContext;
Proxy proxy;
private JREProxyHelper proxyHelper = null;
protected String username = null;
protected String password = null;
/**
* @param directoryOrFileID
* @param listener
*/
public URLFileSystemBrowser(IFileID directoryOrFileID, IRemoteFileSystemListener listener, URL directoryOrFileURL, IConnectContext connectContext, Proxy proxy) {
super(directoryOrFileID, listener);
this.directoryOrFile = directoryOrFileURL;
this.connectContext = connectContext;
this.proxy = proxy;
proxyHelper = new JREProxyHelper();
}
private void setupTimeouts() {
String existingTimeout = System.getProperty(JRE_CONNECT_TIMEOUT_PROPERTY);
if (existingTimeout == null) {
System.setProperty(JRE_CONNECT_TIMEOUT_PROPERTY, DEFAULT_CONNECT_TIMEOUT);
}
existingTimeout = System.getProperty(JRE_READ_TIMEOUT_PROPERTY);
if (existingTimeout == null) {
System.setProperty(JRE_READ_TIMEOUT_PROPERTY, DEFAULT_READ_TIMEOUT);
}
}
/* (non-Javadoc)
* @see org.eclipse.ecf.provider.filetransfer.browse.AbstractFileSystemBrowser#runRequest()
*/
protected void runRequest() throws Exception {
setupProxies();
setupAuthentication();
setupTimeouts();
URLConnection urlConnection = directoryOrFile.openConnection();
// set cache to off if using jar protocol
// this is for addressing bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=235933
if (directoryOrFile.getProtocol().equalsIgnoreCase("jar")) { //$NON-NLS-1$
urlConnection.setUseCaches(false);
}
// Add http 1.1 'Connection: close' header in order to potentially avoid
// server issue described here https://bugs.eclipse.org/bugs/show_bug.cgi?id=234916#c13
// See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=247197
// also see http 1.1 rfc section 14-10 in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
urlConnection.setRequestProperty("Connection", "close"); //$NON-NLS-1$ //$NON-NLS-2$
IURLConnectionModifier connectionModifier = Activator.getDefault().getURLConnectionModifier();
if (connectionModifier != null) {
connectionModifier.setSocketFactoryForConnection(urlConnection);
}
InputStream ins = urlConnection.getInputStream();
ins.close();
remoteFiles = new IRemoteFile[1];
remoteFiles[0] = new URLRemoteFile(urlConnection, fileID);
}
protected void setupAuthentication() throws IOException, UnsupportedCallbackException {
if (connectContext == null)
return;
final CallbackHandler callbackHandler = connectContext.getCallbackHandler();
if (callbackHandler == null)
return;
final NameCallback usernameCallback = new NameCallback(USERNAME_PREFIX);
final ObjectCallback passwordCallback = new ObjectCallback();
// Call callback with username and password callbacks
callbackHandler.handle(new Callback[] {usernameCallback, passwordCallback});
username = usernameCallback.getName();
Object o = passwordCallback.getObject();
if (!(o instanceof String))
throw new UnsupportedCallbackException(passwordCallback, Messages.UrlConnectionRetrieveFileTransfer_UnsupportedCallbackException);
password = (String) passwordCallback.getObject();
// Now set authenticator to our authenticator with user and password
Authenticator.setDefault(new UrlConnectionAuthenticator());
}
class UrlConnectionAuthenticator extends Authenticator {
/* (non-Javadoc)
* @see java.net.Authenticator#getPasswordAuthentication()
*/
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
}
protected void setupProxy(final Proxy proxy2) {
proxyHelper.setupProxy(proxy2);
}
/**
* Select a single proxy from a set of proxies available for the given host. This implementation
* selects in the following manner: 1) If proxies provided is null or array of 0 length, null
* is returned. If only one proxy is available (array of length 1) then the entry is returned.
* If proxies provided is length > 1, then if the type of a proxy in the array matches the given
* protocol (e.g. http, https), then the first matching proxy is returned. If the protocol does
* not match any of the proxies, then the *first* proxy (i.e. proxies[0]) is returned. Subclasses may
* override if desired.
*
* @param protocol the target protocol (e.g. http, https, scp, etc). Will not be <code>null</code>.
* @param proxies the proxies to select from. May be <code>null</code> or array of length 0.
* @return proxy data selected from the proxies provided.
*/
protected IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) {
if (proxies == null || proxies.length == 0)
return null;
// If only one proxy is available, then use that
if (proxies.length == 1)
return proxies[0];
// If more than one proxy is available, then if http/https protocol then look for that
// one...if not found then use first
if (protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$
for (int i = 0; i < proxies.length; i++) {
if (proxies[i].getType().equals(IProxyData.HTTP_PROXY_TYPE))
return proxies[i];
}
} else if (protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$
for (int i = 0; i < proxies.length; i++) {
if (proxies[i].getType().equals(IProxyData.HTTPS_PROXY_TYPE))
return proxies[i];
}
}
// If we haven't found it yet, then return the first one.
return proxies[0];
}
protected void setupProxies() {
// If it's been set directly (via ECF API) then this overrides platform settings
if (proxy == null) {
try {
IProxyService proxyService = Activator.getDefault().getProxyService();
// Only do this if platform service exists
if (proxyService != null) {
// Setup via proxyService entry
URL target = directoryOrFile;
final IProxyData[] proxies = proxyService.getProxyDataForHost(target.getHost());
IProxyData selectedProxy = selectProxyFromProxies(target.getProtocol(), proxies);
if (selectedProxy != null) {
proxy = new Proxy(((selectedProxy.getType().equalsIgnoreCase(IProxyData.SOCKS_PROXY_TYPE)) ? Proxy.Type.SOCKS : Proxy.Type.HTTP), new ProxyAddress(selectedProxy.getHost(), selectedProxy.getPort()), selectedProxy.getUserId(), selectedProxy.getPassword());
}
}
} catch (Exception e) {
// If we don't even have the classes for this (i.e. the org.eclipse.core.net plugin not available)
// then we simply log and ignore
Activator.logNoProxyWarning(e);
} catch (NoClassDefFoundError e) {
Activator.logNoProxyWarning(e);
}
}
if (proxy != null)
setupProxy(proxy);
}
}