diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index cdc057ef9c54..d7d306d2aa1a 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -83,6 +83,7 @@ import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; @@ -3338,7 +3339,13 @@ private int findSeparator(String pattern) { @Restricted(NoExternalUse.class) static class UrlFactory { public URL newURL(String location) throws MalformedURLException { - return new URL(location); + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } } diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 7f3411406780..5438423c6d7e 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -110,7 +110,6 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -1939,11 +1938,11 @@ public String getServerName() { String url = Jenkins.get().getRootUrl(); try { if (url != null) { - String host = new URL(url).getHost(); + String host = new URI(url).toURL().getHost(); if (host != null) return host; } - } catch (MalformedURLException e) { + } catch (MalformedURLException | URISyntaxException e) { // fall back to HTTP request } return Stapler.getCurrentRequest().getServerName(); diff --git a/core/src/main/java/hudson/Main.java b/core/src/main/java/hudson/Main.java index 625fef0c52ee..3e065bf5d7b0 100644 --- a/core/src/main/java/hudson/Main.java +++ b/core/src/main/java/hudson/Main.java @@ -37,6 +37,7 @@ import java.io.Writer; import java.net.HttpRetryException; import java.net.HttpURLConnection; +import java.net.URI; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -99,11 +100,11 @@ public static int remotePost(String[] args) throws Exception { if (!home.endsWith("/")) home = home + '/'; // make sure it ends with '/' // check for authentication info - String auth = new URL(home).getUserInfo(); + String auth = new URI(home).toURL().getUserInfo(); if (auth != null) auth = "Basic " + new Base64Encoder().encode(auth.getBytes(StandardCharsets.UTF_8)); { // check if the home is set correctly - HttpURLConnection con = open(new URL(home)); + HttpURLConnection con = open(new URI(home).toURL()); if (auth != null) con.setRequestProperty("Authorization", auth); con.connect(); if (con.getResponseCode() != 200 @@ -113,7 +114,7 @@ public static int remotePost(String[] args) throws Exception { } } - URL jobURL = new URL(home + "job/" + Util.encode(projectName).replace("/", "/job/") + "/"); + URL jobURL = new URI(home + "job/" + Util.encode(projectName).replace("/", "/job/") + "/").toURL(); { // check if the job name is correct HttpURLConnection con = open(new URL(jobURL, "acceptBuildResult")); @@ -128,8 +129,8 @@ public static int remotePost(String[] args) throws Exception { // get a crumb to pass the csrf check String crumbField = null, crumbValue = null; try { - HttpURLConnection con = open(new URL(home + - "crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)'")); + HttpURLConnection con = open(new URI(home + + "crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)'").toURL()); if (auth != null) con.setRequestProperty("Authorization", auth); String line = IOUtils.readFirstLine(con.getInputStream(), "UTF-8"); String[] components = line.split(":"); @@ -193,7 +194,7 @@ public static int remotePost(String[] args) throws Exception { } catch (HttpRetryException e) { if (e.getLocation() != null) { // retry with the new location - location = new URL(e.getLocation()); + location = new URI(e.getLocation()).toURL(); continue; } // otherwise failed for reasons beyond us. diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index bd627324bb19..4bf5c4b9869f 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -1843,7 +1843,7 @@ static class UrlPluginCopier implements PluginCopier { @Override public void copy(File target) throws Exception { - try (InputStream input = ProxyConfiguration.getInputStream(new URL(url))) { + try (InputStream input = ProxyConfiguration.getInputStream(new URI(url).toURL())) { Files.copy(input, target.toPath()); } } @@ -1945,7 +1945,7 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl @RequirePOST public FormValidation doCheckPluginUrl(StaplerRequest request, @QueryParameter String value) throws IOException { if (StringUtils.isNotBlank(value)) { try { - URL url = new URL(value); + URL url = new URI(value).toURL(); if (!url.getProtocol().startsWith("http")) { return FormValidation.error(Messages.PluginManager_invalidUrl()); } @@ -1953,7 +1953,7 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl if (!url.getProtocol().equals("https")) { return FormValidation.warning(Messages.PluginManager_insecureUrl()); } - } catch (MalformedURLException e) { + } catch (MalformedURLException | URISyntaxException e) { return FormValidation.error(e.getMessage()); } } diff --git a/core/src/main/java/hudson/TcpSlaveAgentListener.java b/core/src/main/java/hudson/TcpSlaveAgentListener.java index 3936071de2ef..e55ff99b2d35 100644 --- a/core/src/main/java/hudson/TcpSlaveAgentListener.java +++ b/core/src/main/java/hudson/TcpSlaveAgentListener.java @@ -38,10 +38,10 @@ import java.io.SequenceInputStream; import java.net.BindException; import java.net.InetSocketAddress; -import java.net.MalformedURLException; import java.net.Socket; import java.net.SocketAddress; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.ServerSocketChannel; import java.nio.charset.StandardCharsets; import java.security.interfaces.RSAPublicKey; @@ -85,8 +85,7 @@ public final class TcpSlaveAgentListener extends Thread { public final int configuredPort; /** - * @param port - * Use 0 to choose a random port. + * @param port Use 0 to choose a random port. */ public TcpSlaveAgentListener(int port) throws IOException { super("TCP agent listener port=" + port); @@ -120,6 +119,7 @@ public int getPort() { /** * Gets the TCP port number in which we are advertising. + * * @since 1.656 */ public int getAdvertisedPort() { @@ -128,21 +128,23 @@ public int getAdvertisedPort() { /** * Gets the host name that we advertise protocol clients to connect to. + * * @since 2.198 */ public String getAdvertisedHost() { if (CLI_HOST_NAME != null) { - return CLI_HOST_NAME; + return CLI_HOST_NAME; } try { - return new URL(Jenkins.get().getRootUrl()).getHost(); - } catch (MalformedURLException e) { + return new URI(Jenkins.get().getRootUrl()).getHost(); + } catch (URISyntaxException e) { throw new IllegalStateException("Could not get TcpSlaveAgentListener host name", e); } } /** * Gets the Base64 encoded public key that forms part of this instance's identity keypair. + * * @return the Base64 encoded public key * @since 2.16 */ @@ -165,6 +167,7 @@ public String getAgentProtocolNames() { /** * Gets Remoting minimum supported version to prevent unsupported agents from connecting + * * @since 2.171 */ public VersionNumber getRemotingMinimumVersion() { @@ -228,9 +231,9 @@ public void shutdown() { private final class ConnectionHandler extends Thread { private static final String DEFAULT_RESPONSE_404 = "HTTP/1.0 404 Not Found\r\n" + - "Content-Type: text/plain;charset=UTF-8\r\n" + - "\r\n" + - "Not Found\r\n"; + "Content-Type: text/plain;charset=UTF-8\r\n" + + "\r\n" + + "Not Found\r\n"; private final Socket s; /** * Unique number to identify this connection. Used in the log. @@ -407,8 +410,8 @@ public boolean connect(Socket socket) throws IOException { socket.getRemoteSocketAddress(), new String(ping, StandardCharsets.UTF_8), responseLength > 0 && responseLength <= response.length ? - new String(response, 0, responseLength, StandardCharsets.UTF_8) : - "bad response length " + responseLength, + new String(response, 0, responseLength, StandardCharsets.UTF_8) : + "bad response length " + responseLength, }); return false; } diff --git a/core/src/main/java/hudson/cli/InstallPluginCommand.java b/core/src/main/java/hudson/cli/InstallPluginCommand.java index cc9d3b59f91d..dfcd410522ee 100644 --- a/core/src/main/java/hudson/cli/InstallPluginCommand.java +++ b/core/src/main/java/hudson/cli/InstallPluginCommand.java @@ -33,6 +33,8 @@ import hudson.util.VersionNumber; import java.io.File; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -104,7 +106,7 @@ protected int run() throws Exception { // is this an URL? try { - URL u = new URL(source); + URL u = new URI(source).toURL(); stdout.println(Messages.InstallPluginCommand_InstallingPluginFromUrl(u)); File f = getTmpFile(); FileUtils.copyURLToFile(u, f); // TODO JENKINS-58248 proxy @@ -113,7 +115,7 @@ protected int run() throws Exception { pm.dynamicLoad(f); } continue; - } catch (MalformedURLException e) { + } catch (MalformedURLException | URISyntaxException e) { // not an URL } diff --git a/core/src/main/java/hudson/model/DownloadService.java b/core/src/main/java/hudson/model/DownloadService.java index b9a5610c4e35..ce0e34e44b3d 100644 --- a/core/src/main/java/hudson/model/DownloadService.java +++ b/core/src/main/java/hudson/model/DownloadService.java @@ -44,6 +44,7 @@ import java.io.InputStream; import java.lang.reflect.Field; import java.net.HttpURLConnection; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; @@ -79,6 +80,7 @@ public class DownloadService { * the prefix for the signature validator name */ private static final String signatureValidatorPrefix = "downloadable"; + /** * Builds up an HTML fragment that starts all the download jobs. * @@ -108,6 +110,7 @@ public Downloadable getById(String id) { * Confusingly, the JSONP files are given the {@code *.json} file extension, when they are really JavaScript and should be {@code *.js}. * This method extracts the JSON from a JSONP URL, since that is what we actually want when we download from the server. * (Currently the true JSON is not published separately, and extracting from the {@code *.json.html} is more work.) + * * @param src a URL to a JSONP file (typically including {@code id} and {@code version} query parameters) * @return the embedded JSON text * @throws IOException if either downloading or processing failed @@ -133,6 +136,7 @@ public static String loadJSON(URL src) throws IOException { /** * Loads JSON from a JSON-with-{@code postMessage} URL. + * * @param src a URL to a JSON HTML file (typically including {@code id} and {@code version} query parameters) * @return the embedded JSON text * @throws IOException if either downloading or processing failed @@ -215,14 +219,13 @@ public static class Downloadable implements ExtensionPoint { /** * Creates a new downloadable. * - * @param id The ID to use. - * @param url - * URL relative to {@link UpdateCenter#getDefaultBaseUrl()}. - * So if this string is "foo.json", the ultimate URL will be - * something like "http://updates.jenkins-ci.org/updates/foo.json" - * - * For security and privacy reasons, we don't allow the retrieval - * from random locations. + * @param id The ID to use. + * @param url URL relative to {@link UpdateCenter#getDefaultBaseUrl()}. + * So if this string is "foo.json", the ultimate URL will be + * something like "http://updates.jenkins-ci.org/updates/foo.json" + *

+ * For security and privacy reasons, we don't allow the retrieval + * from random locations. * @param interval The interval, in milliseconds, between attempts to update this downloadable's data. */ public Downloadable(@NonNull String id, @NonNull String url, long interval) { @@ -286,7 +289,6 @@ public String getId() { * * @param clazz The class to use to generate an ID. * @return The ID generated based on the specified class. - * * @since 2.244 */ @NonNull @@ -322,8 +324,7 @@ public List getUrls() { /** * How often do we retrieve the new image? * - * @return - * number of milliseconds between retrieval. + * @return number of milliseconds between retrieval. */ public long getInterval() { return interval; @@ -388,7 +389,7 @@ public FormValidation updateNow() throws IOException { } String jsonString; try { - jsonString = loadJSONHTML(new URL(site + ".html?id=" + URLEncoder.encode(getId(), StandardCharsets.UTF_8) + "&version=" + URLEncoder.encode(Jenkins.VERSION, StandardCharsets.UTF_8))); + jsonString = loadJSONHTML(new URI(site + ".html?id=" + URLEncoder.encode(getId(), StandardCharsets.UTF_8) + "&version=" + URLEncoder.encode(Jenkins.VERSION, StandardCharsets.UTF_8)).toURL()); toolInstallerMetadataExists = true; } catch (Exception e) { LOGGER.log(Level.FINE, "Could not load json from " + site, e); @@ -416,6 +417,7 @@ public FormValidation updateNow() throws IOException { /** * Function that takes multiple JSONObjects and returns a single one. + * * @param jsonList to be processed * @return a single JSONObject */ @@ -425,9 +427,10 @@ public JSONObject reduce(List jsonList) { /** * check if the list of update center entries has duplicates + * * @param genericList list of entries coming from multiple update centers - * @param comparator the unique ID of an entry - * @param the generic class + * @param comparator the unique ID of an entry + * @param the generic class * @return true if the list has duplicates, false otherwise */ public static boolean hasDuplicates(List genericList, String comparator) { @@ -470,7 +473,6 @@ public static ExtensionList all() { * {@link #idFor(Class)}). * * @param clazz The class to use to determine the downloadable's ID. - * * @since 2.244 */ @CheckForNull diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index 7ea06f20191e..0e04bf1db53a 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -66,6 +66,8 @@ import java.net.HttpRetryException; import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; @@ -1207,7 +1209,13 @@ public UpdateCenterConfiguration() { * @throws IOException if a connection can't be established */ public void checkConnection(ConnectionCheckJob job, String connectionCheckUrl) throws IOException { - testConnection(new URL(connectionCheckUrl)); + try { + testConnection(new URI(connectionCheckUrl).toURL()); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } /** @@ -1230,9 +1238,21 @@ public void checkUpdateCenter(ConnectionCheckJob job, String updateCenterUrl) th static URL toUpdateCenterCheckUrl(String updateCenterUrl) throws MalformedURLException { URL url; if (updateCenterUrl.startsWith("http://") || updateCenterUrl.startsWith("https://")) { - url = new URL(updateCenterUrl + (updateCenterUrl.indexOf('?') == -1 ? "?uctest" : "&uctest")); + try { + url = new URI(updateCenterUrl + (updateCenterUrl.indexOf('?') == -1 ? "?uctest" : "&uctest")).toURL(); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } else { - url = new URL(updateCenterUrl); + try { + url = new URI(updateCenterUrl).toURL(); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } return url; } @@ -2422,7 +2442,13 @@ public PluginDowngradeJob(Plugin plugin, UpdateSite site, Authentication auth) { @Override protected URL getURL() throws MalformedURLException { - return new URL(plugin.url); + try { + return new URI(plugin.url).toURL(); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } @Override @@ -2564,7 +2590,13 @@ protected URL getURL() throws MalformedURLException { if (site == null) { throw new MalformedURLException("no update site defined"); } - return new URL(site.getData().core.url); + try { + return new URI(site.getData().core.url).toURL(); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } @Override diff --git a/core/src/main/java/hudson/model/UpdateSite.java b/core/src/main/java/hudson/model/UpdateSite.java index 1b5b734c7be6..522afbc98962 100644 --- a/core/src/main/java/hudson/model/UpdateSite.java +++ b/core/src/main/java/hudson/model/UpdateSite.java @@ -46,8 +46,9 @@ import hudson.util.VersionNumber; import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; +import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -215,7 +216,13 @@ public long getDataTimestamp() { @Restricted(NoExternalUse.class) public @NonNull FormValidation updateDirectlyNow(boolean signatureCheck) throws IOException { - return updateData(DownloadService.loadJSON(new URL(getUrl() + "?id=" + URLEncoder.encode(getId(), StandardCharsets.UTF_8) + "&version=" + URLEncoder.encode(Jenkins.VERSION, StandardCharsets.UTF_8))), signatureCheck); + try { + return updateData(DownloadService.loadJSON(new URI(getUrl() + "?id=" + URLEncoder.encode(getId(), StandardCharsets.UTF_8) + "&version=" + URLEncoder.encode(Jenkins.VERSION, StandardCharsets.UTF_8)).toURL()), signatureCheck); + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; + } } private FormValidation updateData(String json, boolean signatureCheck) diff --git a/core/src/main/java/hudson/tools/ZipExtractionInstaller.java b/core/src/main/java/hudson/tools/ZipExtractionInstaller.java index 1e1c171f6a95..8fb77e5cfe59 100644 --- a/core/src/main/java/hudson/tools/ZipExtractionInstaller.java +++ b/core/src/main/java/hudson/tools/ZipExtractionInstaller.java @@ -37,9 +37,9 @@ import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -83,8 +83,14 @@ public String getSubdir() { @Override public FilePath performInstallation(ToolInstallation tool, Node node, TaskListener log) throws IOException, InterruptedException { FilePath dir = preferredLocation(tool, node); - if (dir.installIfNecessaryFrom(new URL(url), log, "Unpacking " + url + " to " + dir + " on " + node.getDisplayName())) { - dir.act(new ChmodRecAPlusX()); + try { + if (dir.installIfNecessaryFrom(new URI(url).toURL(), log, "Unpacking " + url + " to " + dir + " on " + node.getDisplayName())) { + dir.act(new ChmodRecAPlusX()); + } + } catch (URISyntaxException e) { + MalformedURLException mex = new MalformedURLException(e.getMessage()); + mex.initCause(e); + throw mex; } if (subdir == null) { return dir;