diff --git a/core/src/main/java/hudson/ProxyConfiguration.java b/core/src/main/java/hudson/ProxyConfiguration.java
index dbe08043f19a..212d97bd4a9f 100644
--- a/core/src/main/java/hudson/ProxyConfiguration.java
+++ b/core/src/main/java/hudson/ProxyConfiguration.java
@@ -357,7 +357,7 @@ public static InputStream getInputStream(URL url) throws IOException {
/**
* Return a new {@link HttpClient} with Jenkins-specific default settings.
*
- *
Equivalent to {@code newHttpClientBuilder().build()}.
+ *
Equivalent to {@code newHttpClientBuilder().followRedirects(HttpClient.Redirect.NORMAL).build()}.
*
*
The Jenkins-specific default settings include a proxy server and proxy authentication (as
* configured by {@link ProxyConfiguration}) and a connection timeout (as configured by {@link
@@ -367,7 +367,7 @@ public static InputStream getInputStream(URL url) throws IOException {
* @since TODO
*/
public static HttpClient newHttpClient() {
- return newHttpClientBuilder().build();
+ return newHttpClientBuilder().followRedirects(HttpClient.Redirect.NORMAL).build();
}
/**
diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java
index 931e47ccf0ed..3b221affef27 100644
--- a/core/src/main/java/hudson/util/FormValidation.java
+++ b/core/src/main/java/hudson/util/FormValidation.java
@@ -44,14 +44,19 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
+import java.util.stream.Stream;
import javax.servlet.ServletException;
import jenkins.model.Jenkins;
import jenkins.util.SystemProperties;
@@ -461,10 +466,46 @@ public static FormValidation validateBase64(String value, boolean allowWhitespac
* This allows the check method to call various utility methods in a concise syntax.
*/
public abstract static class URLCheck {
+ /**
+ * Open the given URI and read text content from it. This method honors the Content-type
+ * header.
+ *
+ * @throws IOException if the URI scheme is not supported, the connection was interrupted,
+ * or the response was an error
+ * @since TODO
+ */
+ protected Stream open(URI uri) throws IOException {
+ HttpClient httpClient = ProxyConfiguration.newHttpClient();
+ HttpRequest httpRequest;
+ try {
+ httpRequest = ProxyConfiguration.newHttpRequestBuilder(uri).GET().build();
+ } catch (IllegalArgumentException e) {
+ throw new IOException(e);
+ }
+ java.net.http.HttpResponse> httpResponse;
+ try {
+ httpResponse =
+ httpClient.send(httpRequest, java.net.http.HttpResponse.BodyHandlers.ofLines());
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ if (httpResponse.statusCode() != HttpURLConnection.HTTP_OK) {
+ throw new IOException(
+ "Server returned HTTP response code "
+ + httpResponse.statusCode()
+ + " for URI "
+ + uri);
+ }
+ return httpResponse.body();
+ }
+
/**
* Opens the given URL and reads text content from it.
* This method honors Content-type header.
+ *
+ * @deprecated use {@link #open(URI)}
*/
+ @Deprecated
protected BufferedReader open(URL url) throws IOException {
// use HTTP content type to find out the charset.
URLConnection con = ProxyConfiguration.open(url);
@@ -475,11 +516,25 @@ protected BufferedReader open(URL url) throws IOException {
new InputStreamReader(con.getInputStream(), getCharset(con)));
}
+ /**
+ * Find the string literal from the given stream of lines.
+ *
+ * @return true if found, false otherwise
+ * @since TODO
+ */
+ protected boolean findText(Stream in, String literal) {
+ try (in) {
+ return in.anyMatch(line -> line.contains(literal));
+ }
+ }
+
/**
* Finds the string literal from the given reader.
* @return
* true if found, false otherwise.
+ * @deprecated use {@link #findText(Stream, String)}
*/
+ @Deprecated
protected boolean findText(BufferedReader in, String literal) throws IOException {
String line;
while ((line = in.readLine()) != null)
@@ -499,9 +554,9 @@ protected FormValidation handleIOException(String url, IOException e) throws IOE
// any invalid URL comes here
if (e.getMessage().equals(url))
// Sun JRE (and probably others too) often return just the URL in the error.
- return error("Unable to connect " + url);
+ return error("Unable to connect " + url, e);
else
- return error(e.getMessage());
+ return error(e.getMessage(), e);
}
/**
diff --git a/core/src/test/java/hudson/util/FormValidationTest.java b/core/src/test/java/hudson/util/FormValidationTest.java
index 1862244d5e53..2d7f2f2576f2 100644
--- a/core/src/test/java/hudson/util/FormValidationTest.java
+++ b/core/src/test/java/hudson/util/FormValidationTest.java
@@ -27,11 +27,15 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import java.net.URI;
import java.util.Arrays;
+import javax.servlet.ServletException;
import org.junit.Test;
/**
@@ -116,4 +120,24 @@ public void formValidationException() {
FormValidation fv = FormValidation.error(new Exception("