Skip to content

Commit 931c7ab

Browse files
authored
SCANJLIB-287 Replace okhttp by the native JDK HttpClient (#268)
1 parent dfb271c commit 931c7ab

File tree

11 files changed

+570
-308
lines changed

11 files changed

+570
-308
lines changed

lib/pom.xml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,6 @@
1818
<!-- provided by the bootstrapper plugin context (Maven, Gradle) -->
1919
<scope>provided</scope>
2020
</dependency>
21-
<dependency>
22-
<groupId>com.squareup.okhttp3</groupId>
23-
<artifactId>okhttp-jvm</artifactId>
24-
</dependency>
25-
<dependency>
26-
<groupId>com.squareup.okhttp3</groupId>
27-
<artifactId>okhttp-urlconnection</artifactId>
28-
</dependency>
29-
<dependency>
30-
<groupId>com.squareup.okhttp3</groupId>
31-
<artifactId>logging-interceptor</artifactId>
32-
</dependency>
3321
<dependency>
3422
<groupId>com.google.code.gson</groupId>
3523
<artifactId>gson</artifactId>

lib/src/main/java/org/sonarsource/scanner/lib/internal/facade/forked/ScannerEngineLauncher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import org.slf4j.LoggerFactory;
3838
import org.sonarsource.scanner.downloadcache.CachedFile;
3939
import org.sonarsource.scanner.lib.ScannerProperties;
40-
import org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory;
40+
import org.sonarsource.scanner.lib.internal.http.HttpClientFactory;
4141
import org.sonarsource.scanner.lib.internal.util.Either;
4242

4343
public class ScannerEngineLauncher {
@@ -117,7 +117,7 @@ private List<String> buildArgs(Map<String, String> properties) {
117117
LOG.info("SONAR_SCANNER_JAVA_OPTS={}", redactSensitiveArguments(split));
118118
args.addAll(split);
119119
}
120-
args.add("-D" + OkHttpClientFactory.BC_IGNORE_USELESS_PASSWD + "=true");
120+
args.add("-D" + HttpClientFactory.BC_IGNORE_USELESS_PASSWD + "=true");
121121
args.add("-jar");
122122
args.add(scannerEngineJar.map(CachedFile::getPath, Function.identity()).toAbsolutePath().toString());
123123
return args;

lib/src/main/java/org/sonarsource/scanner/lib/internal/http/OkHttpClientFactory.java renamed to lib/src/main/java/org/sonarsource/scanner/lib/internal/http/HttpClientFactory.java

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,98 +23,62 @@
2323
import java.io.InputStream;
2424
import java.net.CookieManager;
2525
import java.net.CookiePolicy;
26-
import java.net.HttpURLConnection;
26+
import java.net.InetSocketAddress;
27+
import java.net.ProxySelector;
28+
import java.net.http.HttpClient;
2729
import java.nio.file.Files;
2830
import java.nio.file.Path;
2931
import java.nio.file.StandardOpenOption;
3032
import java.security.KeyStore;
3133
import java.security.KeyStoreException;
3234
import java.security.NoSuchAlgorithmException;
3335
import java.security.cert.CertificateException;
34-
import java.util.Optional;
35-
import java.util.concurrent.TimeUnit;
3636
import javax.annotation.Nullable;
3737
import nl.altindag.ssl.SSLFactory;
3838
import nl.altindag.ssl.exception.GenericKeyStoreException;
3939
import nl.altindag.ssl.util.KeyStoreUtils;
40-
import okhttp3.ConnectionSpec;
41-
import okhttp3.Credentials;
42-
import okhttp3.JavaNetCookieJar;
43-
import okhttp3.OkHttpClient;
44-
import okhttp3.logging.HttpLoggingInterceptor;
4540
import org.bouncycastle.jce.provider.BouncyCastleProvider;
4641
import org.bouncycastle.util.Properties;
4742
import org.slf4j.Logger;
4843
import org.slf4j.LoggerFactory;
4944
import org.sonarsource.scanner.lib.internal.http.ssl.CertificateStore;
5045
import org.sonarsource.scanner.lib.internal.http.ssl.SslConfig;
5146

52-
import static java.nio.charset.StandardCharsets.UTF_8;
53-
import static java.util.Arrays.asList;
54-
import static org.apache.commons.lang3.StringUtils.isNotBlank;
5547
import static org.sonarsource.scanner.lib.ScannerProperties.SONAR_SCANNER_SKIP_SYSTEM_TRUSTSTORE;
5648

57-
public class OkHttpClientFactory {
49+
public class HttpClientFactory {
5850

59-
private static final Logger LOG = LoggerFactory.getLogger(OkHttpClientFactory.class);
51+
private static final Logger LOG = LoggerFactory.getLogger(HttpClientFactory.class);
6052

6153
static final CookieManager COOKIE_MANAGER;
62-
private static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
63-
// use the same cookie jar for all instances
64-
private static final JavaNetCookieJar COOKIE_JAR;
65-
// This property tells Bouncycastle to not fail on empty keystore passwords
6654
public static final String BC_IGNORE_USELESS_PASSWD = "org.bouncycastle.pkcs12.ignore_useless_passwd";
6755

68-
private OkHttpClientFactory() {
69-
// only statics
56+
private HttpClientFactory() {
7057
}
7158

7259
static {
7360
COOKIE_MANAGER = new CookieManager();
7461
COOKIE_MANAGER.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
75-
COOKIE_JAR = new JavaNetCookieJar(COOKIE_MANAGER);
7662
}
7763

78-
static OkHttpClient create(HttpConfig httpConfig) {
79-
64+
static HttpClient create(HttpConfig httpConfig) {
8065
var sslContext = configureSsl(httpConfig.getSslConfig(), httpConfig.skipSystemTruststore());
8166

82-
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder()
83-
.connectTimeout(httpConfig.getConnectTimeout().toMillis(), TimeUnit.MILLISECONDS)
84-
.readTimeout(httpConfig.getSocketTimeout().toMillis(), TimeUnit.MILLISECONDS)
85-
.callTimeout(httpConfig.getResponseTimeout().toMillis(), TimeUnit.MILLISECONDS)
86-
.cookieJar(COOKIE_JAR)
87-
.sslSocketFactory(sslContext.getSslSocketFactory(), sslContext.getTrustManager().orElseThrow());
88-
89-
ConnectionSpec tls = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
90-
.allEnabledTlsVersions()
91-
.allEnabledCipherSuites()
92-
.build();
93-
okHttpClientBuilder.connectionSpecs(asList(tls, ConnectionSpec.CLEARTEXT));
67+
var httpClientBuilder = HttpClient.newBuilder()
68+
.connectTimeout(httpConfig.getConnectTimeout())
69+
.cookieHandler(COOKIE_MANAGER)
70+
.sslContext(sslContext.getSslContext())
71+
.sslParameters(sslContext.getSslParameters())
72+
.followRedirects(HttpClient.Redirect.NEVER);
9473

9574
if (httpConfig.getProxy() != null) {
96-
okHttpClientBuilder.proxy(httpConfig.getProxy());
97-
}
98-
99-
if (isNotBlank(httpConfig.getProxyUser())) {
100-
okHttpClientBuilder.proxyAuthenticator((route, response) -> {
101-
if (response.request().header(PROXY_AUTHORIZATION) != null) {
102-
// Give up, we've already attempted to authenticate.
103-
return null;
104-
}
105-
if (HttpURLConnection.HTTP_PROXY_AUTH == response.code()) {
106-
String credential = Credentials.basic(httpConfig.getProxyUser(), Optional.ofNullable(httpConfig.getProxyPassword()).orElse(""), UTF_8);
107-
return response.request().newBuilder().header(PROXY_AUTHORIZATION, credential).build();
108-
}
109-
return null;
110-
});
75+
var proxyAddress = httpConfig.getProxy().address();
76+
if (proxyAddress instanceof InetSocketAddress) {
77+
httpClientBuilder.proxy(ProxySelector.of((InetSocketAddress) proxyAddress));
78+
}
11179
}
11280

113-
var logging = new HttpLoggingInterceptor(LOG::debug);
114-
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
115-
okHttpClientBuilder.addInterceptor(logging);
116-
117-
return okHttpClientBuilder.build();
81+
return httpClientBuilder.build();
11882
}
11983

12084
private static SSLFactory configureSsl(SslConfig sslConfig, boolean skipSystemTrustMaterial) {

lib/src/main/java/org/sonarsource/scanner/lib/internal/http/HttpException.java

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,28 @@
2020
package org.sonarsource.scanner.lib.internal.http;
2121

2222
import java.net.URL;
23+
import javax.annotation.CheckForNull;
2324
import javax.annotation.Nullable;
2425
import org.apache.commons.lang3.StringUtils;
26+
import org.slf4j.Logger;
2527
import org.slf4j.LoggerFactory;
2628

2729
public class HttpException extends RuntimeException {
30+
private static final Logger LOG = LoggerFactory.getLogger(HttpException.class);
2831
private final int code;
2932

30-
public HttpException(URL requestUrl, int statusCode, String statusText, @Nullable String body) {
31-
super(formatMessage(requestUrl, statusCode, statusText, body));
33+
public HttpException(URL requestUrl, int statusCode, @Nullable String body) {
34+
super(formatMessage(requestUrl, statusCode, body));
3235
this.code = statusCode;
3336
}
3437

35-
private static String formatMessage(URL requestUrl, int code, String statusText, @Nullable String body) {
38+
private static String formatMessage(URL requestUrl, int code, @Nullable String body) {
3639
String message = "GET " + requestUrl + " failed with HTTP " + code;
37-
if (StringUtils.isNotBlank(statusText)) {
38-
message += " " + statusText;
40+
var reasonPhrase = getReasonPhrase(code);
41+
if (reasonPhrase != null) {
42+
message += " " + reasonPhrase;
3943
}
40-
if (LoggerFactory.getLogger(HttpException.class).isDebugEnabled() && StringUtils.isNotBlank(body)) {
44+
if (LOG.isDebugEnabled() && StringUtils.isNotBlank(body)) {
4145
message += "\n" + body;
4246
}
4347
return message;
@@ -47,4 +51,58 @@ public int getCode() {
4751
return code;
4852
}
4953

54+
@CheckForNull
55+
private static String getReasonPhrase(int statusCode) {
56+
switch (statusCode) {
57+
case 200:
58+
return "OK";
59+
case 201:
60+
return "Created";
61+
case 204:
62+
return "No Content";
63+
case 301:
64+
return "Moved Permanently";
65+
case 302:
66+
return "Found";
67+
case 303:
68+
return "See Other";
69+
case 304:
70+
return "Not Modified";
71+
case 307:
72+
return "Temporary Redirect";
73+
case 308:
74+
return "Permanent Redirect";
75+
case 400:
76+
return "Bad Request";
77+
case 401:
78+
return "Unauthorized";
79+
case 403:
80+
return "Forbidden";
81+
case 404:
82+
return "Not Found";
83+
case 405:
84+
return "Method Not Allowed";
85+
case 407:
86+
return "Proxy Authentication Required";
87+
case 408:
88+
return "Request Timeout";
89+
case 409:
90+
return "Conflict";
91+
case 410:
92+
return "Gone";
93+
case 500:
94+
return "Internal Server Error";
95+
case 501:
96+
return "Not Implemented";
97+
case 502:
98+
return "Bad Gateway";
99+
case 503:
100+
return "Service Unavailable";
101+
case 504:
102+
return "Gateway Timeout";
103+
default:
104+
return null;
105+
}
106+
}
107+
50108
}

0 commit comments

Comments
 (0)