diff --git a/java/java-tests/testData/ide/plugins/pluginDescriptor/jar spaces.jar b/java/java-tests/testData/ide/plugins/pluginDescriptor/jar spaces.jar new file mode 100644 index 000000000000..24b8f0daaf48 Binary files /dev/null and b/java/java-tests/testData/ide/plugins/pluginDescriptor/jar spaces.jar differ diff --git a/java/java-tests/testData/ide/plugins/pluginDescriptor/spaces spaces/META-INF/plugin.xml b/java/java-tests/testData/ide/plugins/pluginDescriptor/spaces spaces/META-INF/plugin.xml new file mode 100644 index 000000000000..fd9626d32976 --- /dev/null +++ b/java/java-tests/testData/ide/plugins/pluginDescriptor/spaces spaces/META-INF/plugin.xml @@ -0,0 +1,6 @@ + + URLs Test + com.jetbrains.plugins.urls + + 0.1 + \ No newline at end of file diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java index 7cae6abfb550..a1d6a2b93426 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java @@ -55,6 +55,7 @@ import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -917,13 +918,13 @@ public class PluginManagerCore { private static IdeaPluginDescriptorImpl loadDescriptorFromResource(@NotNull URL resource) { try { if (URLUtil.FILE_PROTOCOL.equals(resource.getProtocol())) { - File descriptorFile = new File(resource.toURI()); + File descriptorFile = urlToFile(resource); File pluginDir = descriptorFile.getParentFile().getParentFile(); return loadDescriptor(pluginDir, descriptorFile.getName()); } else if (URLUtil.JAR_PROTOCOL.equals(resource.getProtocol())) { String path = resource.getFile(); - File pluginJar = new File(new URL(path.substring(0, path.indexOf(URLUtil.JAR_SEPARATOR))).toURI()); + File pluginJar = urlToFile(new URL(path.substring(0, path.indexOf(URLUtil.JAR_SEPARATOR)))); return loadDescriptor(pluginJar, PathUtil.getFileName(path)); } } @@ -934,6 +935,20 @@ public class PluginManagerCore { return null; } + // work around corrupted URLs produced by File.getURL() + private static File urlToFile(URL url) throws URISyntaxException, MalformedURLException { + try { + return new File(url.toURI()); + } + catch (URISyntaxException e) { + String str = url.toString(); + if (str.indexOf(' ') > 0) { + return new File(new URL(StringUtil.replace(str, " ", "%20")).toURI()); + } + throw e; + } + } + private static void loadDescriptorsFromProperty(@NotNull List result) { final String pathProperty = System.getProperty(PROPERTY_PLUGIN_PATH); if (pathProperty == null) return; diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java b/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java index 52a9e8788dd9..c48fae6e2261 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginDescriptorTest.java @@ -16,13 +16,16 @@ package com.intellij.ide.plugins; import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.util.lang.UrlClassLoader; import org.junit.Test; import java.io.File; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.List; +import java.util.Enumeration; +import java.util.NoSuchElementException; import static org.junit.Assert.*; @@ -54,9 +57,62 @@ public class PluginDescriptorTest { public void testFilteringDuplicates() throws MalformedURLException { URL[] urls = { new File(getTestDataPath(), "duplicate1.jar").toURI().toURL(), - new File(getTestDataPath(), "duplicate2.jar").toURI().toURL() - }; - List descriptors = PluginManagerCore.testLoadDescriptorsFromClassPath(new URLClassLoader(urls, null)); - assertEquals(1, descriptors.size()); + new File(getTestDataPath(), "duplicate2.jar").toURI().toURL()}; + assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(new URLClassLoader(urls, null)).size()); + } + + @Test + public void testUrlTolerance() throws MalformedURLException { + class SingleUrlEnumeration implements Enumeration { + private final URL myUrl; + private boolean hasMoreElements = true; + + public SingleUrlEnumeration(URL url) { + myUrl = url; + } + + @Override + public boolean hasMoreElements() { + return hasMoreElements; + } + + @Override + public URL nextElement() { + if (!hasMoreElements) throw new NoSuchElementException(); + hasMoreElements = false; + return myUrl; + } + } + + class TestLoader extends UrlClassLoader { + private final URL myUrl; + + public TestLoader(String prefix, String suffix) throws MalformedURLException { + super(build()); + myUrl = new URL(prefix + new File(getTestDataPath()).toURI().toURL().toString() + suffix + "META-INF/plugin.xml"); + } + + @Override + public URL getResource(String name) { + return null; + } + + @Override + public Enumeration getResources(String name) throws IOException { + return new SingleUrlEnumeration(myUrl); + } + } + + ClassLoader loader1 = new TestLoader("", "/spaces%20spaces/"); + assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader1).size()); + + ClassLoader loader2 = new TestLoader("", "/spaces spaces/"); + assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader2).size()); + + ClassLoader loader3 = new TestLoader("jar:", "/jar%20spaces.jar!/"); + assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader3).size()); + + ClassLoader loader4 = new TestLoader("jar:", "/jar spaces.jar!/"); + assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader4).size()); } } \ No newline at end of file