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 extends IdeaPluginDescriptor> 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