001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.api.utils;
021
022 import com.google.common.base.Joiner;
023 import com.google.common.collect.Lists;
024 import org.apache.commons.io.FileUtils;
025 import org.apache.commons.io.IOUtils;
026 import org.slf4j.LoggerFactory;
027 import org.sonar.api.BatchComponent;
028 import org.sonar.api.ServerComponent;
029 import org.sonar.api.config.Settings;
030 import org.sonar.api.platform.Server;
031
032 import java.io.File;
033 import java.io.FileOutputStream;
034 import java.io.IOException;
035 import java.io.InputStream;
036 import java.net.*;
037 import java.util.List;
038
039 /**
040 * This component downloads HTTP files
041 *
042 * @since 2.2
043 */
044 public class HttpDownloader implements BatchComponent, ServerComponent {
045
046 public static final int TIMEOUT_MILLISECONDS = 20 * 1000;
047
048 private String userAgent;
049
050 public HttpDownloader(Server server, Settings settings) {
051 this(settings, server.getVersion());
052 }
053
054 public HttpDownloader(Settings settings) {
055 this(settings, null);
056 }
057
058 private HttpDownloader(Settings settings, String userAgent) {
059 initProxy(settings);
060 initUserAgent(userAgent);
061 }
062
063 private void initProxy(Settings settings) {
064 propagateProxySystemProperties(settings);
065 if (requiresProxyAuthentication(settings)) {
066 registerProxyCredentials(settings);
067 }
068 }
069
070 private void initUserAgent(String sonarVersion) {
071 userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion));
072 System.setProperty("http.agent", userAgent);
073 }
074
075 public String getProxySynthesis(URI uri) {
076 return getProxySynthesis(uri, ProxySelector.getDefault());
077 }
078
079 static String getProxySynthesis(URI uri, ProxySelector proxySelector) {
080 List<String> descriptions = Lists.newArrayList();
081 List<Proxy> proxies = proxySelector.select(uri);
082 if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) {
083 descriptions.add("no proxy");
084 } else {
085 for (Proxy proxy : proxies) {
086 if (!proxy.type().equals(Proxy.Type.DIRECT)) {
087 descriptions.add("proxy: " + proxy.address().toString());
088 }
089 }
090 }
091 return Joiner.on(", ").join(descriptions);
092 }
093
094 private void registerProxyCredentials(Settings settings) {
095 Authenticator.setDefault(new ProxyAuthenticator(settings.getString("http.proxyUser"), settings
096 .getString("http.proxyPassword")));
097 }
098
099 private boolean requiresProxyAuthentication(Settings settings) {
100 return settings.getString("http.proxyUser") != null;
101 }
102
103 private void propagateProxySystemProperties(Settings settings) {
104 propagateSystemProperty(settings, "http.proxyHost");
105 propagateSystemProperty(settings, "http.proxyPort");
106 propagateSystemProperty(settings, "http.nonProxyHosts");
107 propagateSystemProperty(settings, "http.auth.ntlm.domain");
108 propagateSystemProperty(settings, "socksProxyHost");
109 propagateSystemProperty(settings, "socksProxyPort");
110 }
111
112 private void propagateSystemProperty(Settings settings, String key) {
113 if (settings.getString(key) != null) {
114 System.setProperty(key, settings.getString(key));
115 }
116 }
117
118 public void download(URI uri, File toFile) {
119 InputStream input = null;
120 FileOutputStream output = null;
121 try {
122 HttpURLConnection connection = newHttpConnection(uri);
123 output = new FileOutputStream(toFile, false);
124 input = connection.getInputStream();
125 IOUtils.copy(input, output);
126
127 } catch (Exception e) {
128 IOUtils.closeQuietly(output);
129 FileUtils.deleteQuietly(toFile);
130 throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e);
131
132 } finally {
133 IOUtils.closeQuietly(input);
134 IOUtils.closeQuietly(output);
135 }
136 }
137
138 public byte[] download(URI uri) {
139 InputStream input = null;
140 try {
141 HttpURLConnection connection = newHttpConnection(uri);
142 input = connection.getInputStream();
143 return IOUtils.toByteArray(input);
144
145 } catch (Exception e) {
146 throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e);
147
148 } finally {
149 IOUtils.closeQuietly(input);
150 }
151 }
152
153 public String downloadPlainText(URI uri, String encoding) {
154 InputStream input = null;
155 try {
156 HttpURLConnection connection = newHttpConnection(uri);
157 input = connection.getInputStream();
158 return IOUtils.toString(input, encoding);
159
160 } catch (Exception e) {
161 throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e);
162
163 } finally {
164 IOUtils.closeQuietly(input);
165 }
166 }
167
168 public InputStream openStream(URI uri) {
169 try {
170 HttpURLConnection connection = newHttpConnection(uri);
171 return connection.getInputStream();
172
173 } catch (Exception e) {
174 throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e);
175 }
176 }
177
178 private HttpURLConnection newHttpConnection(URI uri) throws IOException {
179 LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri) + ")");
180 HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
181 connection.setConnectTimeout(TIMEOUT_MILLISECONDS);
182 connection.setReadTimeout(TIMEOUT_MILLISECONDS);
183 connection.setUseCaches(true);
184 connection.setInstanceFollowRedirects(true);
185 connection.setRequestProperty("User-Agent", userAgent);
186 return connection;
187 }
188 }
189
190 class ProxyAuthenticator extends Authenticator {
191 private PasswordAuthentication auth;
192
193 ProxyAuthenticator(String user, String password) {
194 auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray());
195 }
196
197 protected PasswordAuthentication getPasswordAuthentication() {
198 return auth;
199 }
200 }