|
|
@@ -20,14 +20,15 @@ |
|
|
|
package org.sonar.api.utils; |
|
|
|
|
|
|
|
import com.google.common.annotations.VisibleForTesting; |
|
|
|
|
|
|
|
import com.google.common.base.Joiner; |
|
|
|
import com.google.common.base.Strings; |
|
|
|
import com.google.common.collect.ImmutableList; |
|
|
|
import com.google.common.collect.Lists; |
|
|
|
import com.google.common.io.ByteStreams; |
|
|
|
import com.google.common.io.CharStreams; |
|
|
|
import com.google.common.io.Files; |
|
|
|
import com.google.common.io.InputSupplier; |
|
|
|
import org.apache.commons.codec.binary.Base64; |
|
|
|
import org.apache.commons.io.FileUtils; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.sonar.api.BatchComponent; |
|
|
@@ -53,75 +54,16 @@ import java.util.List; |
|
|
|
* @since 2.2 |
|
|
|
*/ |
|
|
|
public class HttpDownloader extends UriReader.SchemeProcessor implements BatchComponent, ServerComponent { |
|
|
|
|
|
|
|
public static final int TIMEOUT_MILLISECONDS = 20 * 1000; |
|
|
|
private static final List<String> PROXY_SETTINGS = ImmutableList.of( |
|
|
|
"http.proxyHost", "http.proxyPort", "http.nonProxyHosts", |
|
|
|
"http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort"); |
|
|
|
|
|
|
|
private String userAgent; |
|
|
|
private final BaseHttpDownloader downloader; |
|
|
|
|
|
|
|
public HttpDownloader(Server server, Settings settings) { |
|
|
|
this(settings, server.getVersion()); |
|
|
|
downloader = new BaseHttpDownloader(settings, server.getVersion()); |
|
|
|
} |
|
|
|
|
|
|
|
public HttpDownloader(Settings settings) { |
|
|
|
this(settings, null); |
|
|
|
} |
|
|
|
|
|
|
|
private HttpDownloader(Settings settings, String userAgent) { |
|
|
|
initProxy(settings); |
|
|
|
initUserAgent(userAgent); |
|
|
|
} |
|
|
|
|
|
|
|
private void initProxy(Settings settings) { |
|
|
|
propagateProxySystemProperties(settings); |
|
|
|
if (requiresProxyAuthentication(settings)) { |
|
|
|
registerProxyCredentials(settings); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void initUserAgent(String sonarVersion) { |
|
|
|
userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion)); |
|
|
|
System.setProperty("http.agent", userAgent); |
|
|
|
} |
|
|
|
|
|
|
|
public String getProxySynthesis(URI uri) { |
|
|
|
return getProxySynthesis(uri, ProxySelector.getDefault()); |
|
|
|
} |
|
|
|
|
|
|
|
@VisibleForTesting |
|
|
|
static String getProxySynthesis(URI uri, ProxySelector proxySelector) { |
|
|
|
List<Proxy> proxies = proxySelector.select(uri); |
|
|
|
if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) { |
|
|
|
return "no proxy"; |
|
|
|
} |
|
|
|
|
|
|
|
List<String> descriptions = Lists.newArrayList(); |
|
|
|
for (Proxy proxy : proxies) { |
|
|
|
if (proxy.type() != Proxy.Type.DIRECT) { |
|
|
|
descriptions.add("proxy: " + proxy.address()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Joiner.on(", ").join(descriptions); |
|
|
|
} |
|
|
|
|
|
|
|
private void registerProxyCredentials(Settings settings) { |
|
|
|
Authenticator.setDefault(new ProxyAuthenticator(settings.getString("http.proxyUser"), settings |
|
|
|
.getString("http.proxyPassword"))); |
|
|
|
} |
|
|
|
|
|
|
|
private boolean requiresProxyAuthentication(Settings settings) { |
|
|
|
return settings.getString("http.proxyUser") != null; |
|
|
|
} |
|
|
|
|
|
|
|
private void propagateProxySystemProperties(Settings settings) { |
|
|
|
for (String key : PROXY_SETTINGS) { |
|
|
|
if (settings.getString(key) != null) { |
|
|
|
System.setProperty(key, settings.getString(key)); |
|
|
|
} |
|
|
|
} |
|
|
|
downloader = new BaseHttpDownloader(settings, null); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
@@ -136,41 +78,45 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo |
|
|
|
|
|
|
|
@Override |
|
|
|
byte[] readBytes(URI uri) { |
|
|
|
try { |
|
|
|
return ByteStreams.toByteArray(new HttpInputSupplier(uri)); |
|
|
|
} catch (IOException e) { |
|
|
|
throw failToDownload(uri, e); |
|
|
|
} |
|
|
|
return download(uri); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
String readString(URI uri, Charset charset) { |
|
|
|
try { |
|
|
|
return CharStreams.toString(CharStreams.newReaderSupplier(new HttpInputSupplier(uri), charset)); |
|
|
|
return CharStreams.toString(CharStreams.newReaderSupplier(downloader.newInputSupplier(uri), charset)); |
|
|
|
} catch (IOException e) { |
|
|
|
throw failToDownload(uri, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public String downloadPlainText(URI uri, String encoding) { |
|
|
|
return readString(uri, Charset.forName(encoding)); |
|
|
|
} |
|
|
|
|
|
|
|
public byte[] download(URI uri) { |
|
|
|
return readBytes(uri); |
|
|
|
try { |
|
|
|
return ByteStreams.toByteArray(downloader.newInputSupplier(uri)); |
|
|
|
} catch (IOException e) { |
|
|
|
throw failToDownload(uri, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public String downloadPlainText(URI uri, String encoding) { |
|
|
|
return readString(uri, Charset.forName(encoding)); |
|
|
|
public String getProxySynthesis(URI uri) { |
|
|
|
return downloader.getProxySynthesis(uri); |
|
|
|
} |
|
|
|
|
|
|
|
public InputStream openStream(URI uri) { |
|
|
|
try { |
|
|
|
return new HttpInputSupplier(uri).getInput(); |
|
|
|
} catch (Exception e) { |
|
|
|
throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e); |
|
|
|
return downloader.newInputSupplier(uri).getInput(); |
|
|
|
} catch (IOException e) { |
|
|
|
throw failToDownload(uri, e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void download(URI uri, File toFile) { |
|
|
|
try { |
|
|
|
Files.copy(new HttpInputSupplier(uri), toFile); |
|
|
|
Files.copy(downloader.newInputSupplier(uri), toFile); |
|
|
|
} catch (IOException e) { |
|
|
|
FileUtils.deleteQuietly(toFile); |
|
|
|
throw failToDownload(uri, e); |
|
|
@@ -178,39 +124,121 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo |
|
|
|
} |
|
|
|
|
|
|
|
private SonarException failToDownload(URI uri, IOException e) { |
|
|
|
return new SonarException(String.format("Fail to download the file: %s (%s)", uri, getProxySynthesis(uri)), e); |
|
|
|
throw new SonarException(String.format("Fail to download: %s (%s)", uri, getProxySynthesis(uri)), e); |
|
|
|
} |
|
|
|
|
|
|
|
class HttpInputSupplier implements InputSupplier<InputStream> { |
|
|
|
private final URI uri; |
|
|
|
public static class BaseHttpDownloader { |
|
|
|
private static final List<String> PROXY_SETTINGS = ImmutableList.of( |
|
|
|
"http.proxyHost", "http.proxyPort", "http.nonProxyHosts", |
|
|
|
"http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort"); |
|
|
|
|
|
|
|
HttpInputSupplier(URI uri) { |
|
|
|
this.uri = uri; |
|
|
|
private String userAgent; |
|
|
|
|
|
|
|
public BaseHttpDownloader(Settings settings, String userAgent) { |
|
|
|
initProxy(settings); |
|
|
|
initUserAgent(userAgent); |
|
|
|
} |
|
|
|
|
|
|
|
public InputStream getInput() throws IOException { |
|
|
|
LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri) + ")"); |
|
|
|
private void initProxy(Settings settings) { |
|
|
|
propagateProxySystemProperties(settings); |
|
|
|
if (requiresProxyAuthentication(settings)) { |
|
|
|
registerProxyCredentials(settings); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection(); |
|
|
|
connection.setConnectTimeout(TIMEOUT_MILLISECONDS); |
|
|
|
connection.setReadTimeout(TIMEOUT_MILLISECONDS); |
|
|
|
connection.setUseCaches(true); |
|
|
|
connection.setInstanceFollowRedirects(true); |
|
|
|
connection.setRequestProperty("User-Agent", userAgent); |
|
|
|
return connection.getInputStream(); |
|
|
|
private void initUserAgent(String sonarVersion) { |
|
|
|
userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion)); |
|
|
|
System.setProperty("http.agent", userAgent); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class ProxyAuthenticator extends Authenticator { |
|
|
|
private PasswordAuthentication auth; |
|
|
|
private String getProxySynthesis(URI uri) { |
|
|
|
return getProxySynthesis(uri, ProxySelector.getDefault()); |
|
|
|
} |
|
|
|
|
|
|
|
ProxyAuthenticator(String user, String password) { |
|
|
|
auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray()); |
|
|
|
} |
|
|
|
@VisibleForTesting |
|
|
|
static String getProxySynthesis(URI uri, ProxySelector proxySelector) { |
|
|
|
List<Proxy> proxies = proxySelector.select(uri); |
|
|
|
if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) { |
|
|
|
return "no proxy"; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected PasswordAuthentication getPasswordAuthentication() { |
|
|
|
return auth; |
|
|
|
List<String> descriptions = Lists.newArrayList(); |
|
|
|
for (Proxy proxy : proxies) { |
|
|
|
if (proxy.type() != Proxy.Type.DIRECT) { |
|
|
|
descriptions.add("proxy: " + proxy.address()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Joiner.on(", ").join(descriptions); |
|
|
|
} |
|
|
|
|
|
|
|
private void registerProxyCredentials(Settings settings) { |
|
|
|
Authenticator.setDefault(new ProxyAuthenticator( |
|
|
|
settings.getString("http.proxyUser"), |
|
|
|
settings.getString("http.proxyPassword"))); |
|
|
|
} |
|
|
|
|
|
|
|
private boolean requiresProxyAuthentication(Settings settings) { |
|
|
|
return settings.getString("http.proxyUser") != null; |
|
|
|
} |
|
|
|
|
|
|
|
private void propagateProxySystemProperties(Settings settings) { |
|
|
|
for (String key : PROXY_SETTINGS) { |
|
|
|
if (settings.getString(key) != null) { |
|
|
|
System.setProperty(key, settings.getString(key)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public InputSupplier<InputStream> newInputSupplier(URI uri) { |
|
|
|
return new HttpInputSupplier(uri, userAgent, null, null); |
|
|
|
} |
|
|
|
|
|
|
|
public InputSupplier<InputStream> newInputSupplier(URI uri, String login, String password) { |
|
|
|
return new HttpInputSupplier(uri, userAgent, login, password); |
|
|
|
} |
|
|
|
|
|
|
|
private static class HttpInputSupplier implements InputSupplier<InputStream> { |
|
|
|
private final String login; |
|
|
|
private final String password; |
|
|
|
private final URI uri; |
|
|
|
private final String userAgent; |
|
|
|
|
|
|
|
HttpInputSupplier(URI uri, String userAgent, String login, String password) { |
|
|
|
this.uri = uri; |
|
|
|
this.userAgent = userAgent; |
|
|
|
this.login = login; |
|
|
|
this.password = password; |
|
|
|
} |
|
|
|
|
|
|
|
public InputStream getInput() throws IOException { |
|
|
|
LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri, ProxySelector.getDefault()) + ")"); |
|
|
|
|
|
|
|
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection(); |
|
|
|
if (!Strings.isNullOrEmpty(login)) { |
|
|
|
String encoded = new String(Base64.encodeBase64((login + ":" + password).getBytes())); |
|
|
|
connection.setRequestProperty("Authorization", "Basic " + encoded); |
|
|
|
} |
|
|
|
connection.setConnectTimeout(TIMEOUT_MILLISECONDS); |
|
|
|
connection.setReadTimeout(TIMEOUT_MILLISECONDS); |
|
|
|
connection.setUseCaches(true); |
|
|
|
connection.setInstanceFollowRedirects(true); |
|
|
|
connection.setRequestProperty("User-Agent", userAgent); |
|
|
|
return connection.getInputStream(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static class ProxyAuthenticator extends Authenticator { |
|
|
|
private final PasswordAuthentication auth; |
|
|
|
|
|
|
|
ProxyAuthenticator(String user, String password) { |
|
|
|
auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray()); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected PasswordAuthentication getPasswordAuthentication() { |
|
|
|
return auth; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |