<artifactId>fest-assert</artifactId>
<version>1.4</version>
</dependency>
+ <dependency>
+ <groupId>com.github.kevinsawicki</groupId>
+ <artifactId>http-request</artifactId>
+ <version>4.1</version>
+ </dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
- <relocations>
- <relocation>
- <pattern>org.apache.commons.lang</pattern>
- <shadedPattern>org.sonar.runner.commonslang</shadedPattern>
- </relocation>
- </relocations>
</configuration>
</execution>
</executions>
<configuration>
<rules>
<requireFilesSize>
- <minsize>220000</minsize>
- <maxsize>240000</maxsize>
+ <minsize>250000</minsize>
+ <maxsize>300000</maxsize>
<files>
<file>${pom.build.directory}/sonar-runner-${pom.version}.zip</file>
</files>
<name>Sonar Runner - Implementation</name>
<dependencies>
+ <dependency>
+ <groupId>com.github.kevinsawicki</groupId>
+ <artifactId>http-request</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-home</artifactId>
<version>${pom.version}</version>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>com.google.code.findbugs</groupId>
- <artifactId>jsr305</artifactId>
- <scope>provided</scope>
- </dependency>
<!-- unit tests -->
<dependency>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
+ <relocations>
+ <relocation>
+ <pattern>com.github.kevinsawicki.http</pattern>
+ <shadedPattern>org.sonar.runner.kevinsawicki</shadedPattern>
+ </relocation>
+ </relocations>
</configuration>
</execution>
</executions>
*/
package org.sonar.runner.impl;
+import com.github.kevinsawicki.http.HttpRequest;
import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
import java.net.ConnectException;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Properties;
}
void download(String path, File toFile) {
- InputStream input = null;
- FileOutputStream output = null;
String fullUrl = serverUrl + path;
try {
Logs.debug("Download " + fullUrl + " to " + toFile.getAbsolutePath());
- HttpURLConnection connection = newHttpConnection(new URL(fullUrl));
- int statusCode = connection.getResponseCode();
- if (statusCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
+ HttpRequest httpRequest = newHttpRequest(new URL(fullUrl));
+ if (!httpRequest.ok()) {
+ throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + httpRequest.code());
}
- output = new FileOutputStream(toFile, false);
- input = connection.getInputStream();
- IOUtils.copyLarge(input, output);
+ httpRequest.receive(toFile);
} catch (Exception e) {
- if (e instanceof ConnectException || e instanceof UnknownHostException) {
+ if (e.getCause() instanceof ConnectException || e.getCause() instanceof UnknownHostException) {
Logs.error("Sonar server '" + serverUrl + "' can not be reached");
}
- IOUtils.closeQuietly(output);
FileUtils.deleteQuietly(toFile);
throw new IllegalStateException("Fail to download: " + fullUrl, e);
- } finally {
- IOUtils.closeQuietly(input);
- IOUtils.closeQuietly(output);
}
}
String downloadString(String path) throws IOException {
String fullUrl = serverUrl + path;
- HttpURLConnection conn = newHttpConnection(new URL(fullUrl));
- String charset = getCharsetFromContentType(conn.getContentType());
- if (charset == null || "".equals(charset)) {
- charset = "UTF-8";
- }
- Reader reader = null;
+ HttpRequest httpRequest = newHttpRequest(new URL(fullUrl));
try {
- int statusCode = conn.getResponseCode();
- if (statusCode != HttpURLConnection.HTTP_OK) {
- throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + statusCode);
+ String charset = getCharsetFromContentType(httpRequest.contentType());
+ if (charset == null || "".equals(charset)) {
+ charset = "UTF-8";
+ }
+ if (!httpRequest.ok()) {
+ throw new IOException("Status returned by url : '" + fullUrl + "' is invalid : " + httpRequest.code());
}
- reader = new InputStreamReader(conn.getInputStream(), charset);
- return IOUtils.toString(reader);
- } catch (IOException e) {
- if (e instanceof ConnectException || e instanceof UnknownHostException) {
+ return httpRequest.body(charset);
+
+ } catch (HttpRequest.HttpRequestException e) {
+ if (e.getCause() instanceof ConnectException || e.getCause() instanceof UnknownHostException) {
Logs.error("Sonar server '" + serverUrl + "' can not be reached");
}
throw e;
} finally {
- IOUtils.closeQuietly(reader);
- conn.disconnect();
+ httpRequest.disconnect();
}
}
- private HttpURLConnection newHttpConnection(URL url) throws IOException {
- //TODO send credentials
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS);
- connection.setReadTimeout(READ_TIMEOUT_MILLISECONDS);
- connection.setInstanceFollowRedirects(true);
- connection.setRequestMethod("GET");
- connection.setRequestProperty("User-Agent", userAgent);
- return connection;
+ private HttpRequest newHttpRequest(URL url) {
+ HttpRequest request = HttpRequest.get(url);
+ request.trustAllCerts().trustAllHosts();
+ request.acceptGzipEncoding().uncompress(true);
+ request.connectTimeout(CONNECT_TIMEOUT_MILLISECONDS).readTimeout(READ_TIMEOUT_MILLISECONDS);
+ request.userAgent(userAgent);
+
+ // TODO send credentials
+ return request;
}
/**
--- /dev/null
+/*
+ * Sonar Runner - Implementation
+ * Copyright (C) 2011 SonarSource
+ * dev@sonar.codehaus.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.runner.impl;
+
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Arrays;
+import java.util.List;
+
+class NetworkUtil {
+ static int getNextAvailablePort() {
+ for (int index = 0; index < 5; index++) {
+ try {
+ ServerSocket socket = new ServerSocket(0);
+ int unusedPort = socket.getLocalPort();
+ socket.close();
+ if (isValidPort(unusedPort)) {
+ return unusedPort;
+ }
+
+ } catch (IOException e) {
+ throw new IllegalStateException("Can not find an open network port", e);
+ }
+ }
+ throw new IllegalStateException("Can not find an open network port");
+ }
+
+ // Firefox blocks some reserverd ports : http://www-archive.mozilla.org/projects/netlib/PortBanning.html
+ private static final List<Integer> BLOCKED_PORTS = Arrays.asList(2049, 4045, 6000);
+
+ static boolean isValidPort(int port) {
+ return port > 1023 && !BLOCKED_PORTS.contains(port);
+ }
+}
import java.util.Properties;
import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
public class ServerConnectionTest {
assertThat(FileUtils.readFileToString(toFile)).isEqualTo("abcde");
}
+
+ @Test
+ public void should_not_download_file_when_host_is_down() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort());
+
+ ServerConnection connection = ServerConnection.create(props);
+ File toFile = temp.newFile();
+ try {
+ connection.download("/batch/index.txt", toFile);
+ fail();
+ } catch (Exception e) {
+ // success
+ }
+ }
+
+ @Test
+ public void should_not_download_string_when_host_is_down() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("sonar.host.url", "http://localhost:" + NetworkUtil.getNextAvailablePort());
+
+ ServerConnection connection = ServerConnection.create(props);
+ File toFile = temp.newFile();
+ try {
+ connection.download("/batch/index.txt", toFile);
+ fail();
+ } catch (Exception e) {
+ // success
+ }
+ }
}