﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc
15274	[Patch] Support URLs with other protocol than `http` or `https` for plugin sites	floscher	team	"== The problem I'm trying to solve

I tried to point JOSM to a custom plugin site using a `file://` URL, but it didn't work. I was able to add the site, but when clicking `download list`, nothing happened. JOSM didn't complain, but also didn't download anything.

== Why the problem exists

`PluginDownloadTask` and `ReadRemotePluginInformationTask` use `HttpClient` for downloading, which does seem to support `file://` URLs.

== How I try to solve the problem

For URLs with protocol `http` or `https` everything stays the same (i.e. `HttpClient` is used), but for other URLs the download happens via `url.openConnection().getInputStream()`.

With the changes applied I can now ""download"" a plugin list (like the one at https://josm.openstreetmap.de/plugin) that is located on my local filesystem. And I can even ""download"" a plugin *.jar file from my local filesystem, which the plugin list from my local filesystem references.

== My proposed changes

{{{#!diff
diff --git a/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java b/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java
index 40231cb4c5..fcb5858867 100644
--- a/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java
+++ b/src/org/openstreetmap/josm/plugins/PluginDownloadTask.java
@@ -121,12 +121,20 @@ public class PluginDownloadTask extends PleaseWaitRunnable {
                 throw new PluginDownloadException(msg);
             }
             URL url = new URL(pi.downloadlink);
-            synchronized (this) {
-                downloadConnection = HttpClient.create(url).setAccept(PLUGIN_MIME_TYPES);
-                downloadConnection.connect();
-            }
-            try (InputStream in = downloadConnection.getResponse().getContent()) {
-                Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            Logging.debug(""Download plugin {0} from {1}..."", pi.name, url);
+            if (""https"".equals(url.getProtocol()) || ""http"".equals(url.getProtocol())) {
+                synchronized (this) {
+                    downloadConnection = HttpClient.create(url).setAccept(PLUGIN_MIME_TYPES);
+                    downloadConnection.connect();
+                }
+                try (InputStream in = downloadConnection.getResponse().getContent()) {
+                    Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+                }
+            } else {
+                // this is an alternative for e.g. file:// URLs where HttpClient doesn't work
+                try (InputStream in = url.openConnection().getInputStream()) {
+                    Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+                }
             }
         } catch (MalformedURLException e) {
             String msg = tr(""Cannot download plugin ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download."",
diff --git a/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java b/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
index 324a33121a..aa3012b083 100644
--- a/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
+++ b/src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
@@ -10,6 +10,7 @@ import java.io.File;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -154,14 +155,31 @@ public class ReadRemotePluginInformationTask extends PleaseWaitRunnable {
             monitor.beginTask("""");
             monitor.indeterminateSubTask(tr(""Downloading plugin list from ''{0}''"", printsite));
 
-            URL url = new URL(site);
-            connection = HttpClient.create(url).useCache(false);
-            final HttpClient.Response response = connection.connect();
-            content = response.fetchContent();
-            if (response.getResponseCode() != 200) {
-                throw new IOException(tr(""Unsuccessful HTTP request""));
+            final URL url = new URL(site);
+            if (""https"".equals(url.getProtocol()) || ""http"".equals(url.getProtocol())) {
+                connection = HttpClient.create(url).useCache(false);
+                final HttpClient.Response response = connection.connect();
+                content = response.fetchContent();
+                if (response.getResponseCode() != 200) {
+                    throw new IOException(tr(""Unsuccessful HTTP request""));
+                }
+                return content;
+            } else {
+                // e.g. when downloading from a file:// URL, we can't use HttpClient
+                try (InputStreamReader in = new InputStreamReader(url.openConnection().getInputStream(), StandardCharsets.UTF_8)) {
+                    final StringBuilder sb = new StringBuilder();
+                    final char[] buffer = new char[8192];
+                    int numChars;
+                    while ((numChars = in.read(buffer)) >= 0) {
+                        sb.append(buffer, 0, numChars);
+                        if (canceled) {
+                            return null;
+                        }
+                    }
+                    return sb.toString();
+                }
             }
-            return content;
+
         } catch (MalformedURLException e) {
             if (canceled) return null;
             Logging.error(e);
}}}"	enhancement	closed	normal	17.09	Core		fixed		
