From 519c77d41679c710470a3fc933330d7ce48636d2 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 13 Jun 2018 22:39:02 +0300 Subject: [PATCH] PY-29977 Don't access external doc URLs to validate them in getUrlFor() This method is used both to check possible sources of external documentation in DefaultDocumentationCollector#getDocumentation() (executed inside a read action) and to show links at the end of Quick Documentation in DocumentationComponent (happens on EDT). In both cases network access may badly affect editor responsiveness. The correct approach here is to provide the most accurate URL right away in PythonDocumentationMap and PythonDocumentationProvider implementations instead of falling back to the documentation root. As a result, PythonDocumentationLinkProvider#getExternalDocumentationURL is no longer necessary and thus deprecated. --- .../PythonDocumentationLinkProvider.java | 11 ++++++- .../documentation/PythonDocumentationMap.java | 10 ------ .../PythonDocumentationProvider.java | 32 ++----------------- 3 files changed, 13 insertions(+), 40 deletions(-) diff --git a/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java index 720a8be9b179..dad44a6740ac 100644 --- a/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java +++ b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationLinkProvider.java @@ -29,5 +29,14 @@ public interface PythonDocumentationLinkProvider { @Nullable String getExternalDocumentationUrl(PsiElement element, PsiElement originalElement); - String getExternalDocumentationRoot(Sdk sdk); + /** + * This method was used to provide the fallback URL in case the one returned by {@link #getExternalDocumentationUrl(PsiElement, PsiElement)} + * doesn't exist. This check is not performed any longer to avoid UI sluggishness. + * + * @deprecated Do your best to provide a valid URL in {@link #getExternalDocumentationUrl(PsiElement, PsiElement)} + */ + @Deprecated + default String getExternalDocumentationRoot(Sdk sdk) { + return ""; + } } diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java index a102186fd7d5..2fa9291759a1 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java @@ -148,16 +148,6 @@ public class PythonDocumentationMap implements PersistentStateComponent= 0 ? urlPattern.substring(0, pos) : urlPattern; diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index 4b3eb172c5cb..e1c62ce172cc 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -21,7 +21,6 @@ import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; -import com.intellij.util.io.HttpRequests; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; @@ -46,7 +45,6 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; -import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -535,12 +533,12 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i @Override public List getUrlFor(PsiElement element, PsiElement originalElement) { - final String url = getUrlFor(element, originalElement, true); + final String url = getOnlyUrlFor(element, originalElement); return url == null ? null : Collections.singletonList(url); } @Nullable - public static String getUrlFor(PsiElement element, PsiElement originalElement, boolean checkExistence) { + public static String getOnlyUrlFor(PsiElement element, PsiElement originalElement) { PsiFileSystemItem file = element instanceof PsiFileSystemItem ? (PsiFileSystemItem)element : element.getContainingFile(); if (file == null) return null; if (PyNames.INIT_DOT_PY.equals(file.getName())) { @@ -568,41 +566,17 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } final String url = map.urlFor(qName, namedElement, pyVersion); if (url != null) { - if (checkExistence && !pageExists(url)) { - return map.rootUrlFor(qName); - } return url; } for (PythonDocumentationLinkProvider provider : Extensions.getExtensions(PythonDocumentationLinkProvider.EP_NAME)) { final String providerUrl = provider.getExternalDocumentationUrl(element, originalElement); if (providerUrl != null) { - if (checkExistence && !pageExists(providerUrl)) { - return provider.getExternalDocumentationRoot(sdk); - } return providerUrl; } } return null; } - private static boolean pageExists(@NotNull String url) { - if (new File(url).exists()) { - return true; - } - try { - HttpRequests.head(url).tryConnect(); - } - catch (HttpRequests.HttpStatusException e) { - return false; - } - catch (IllegalArgumentException e) { - return false; - } - catch (IOException ignored) { - } - return true; - } - @Nullable public static String pyVersion(@Nullable String versionString) { final String prefix = "Python "; @@ -683,7 +657,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i @Override public boolean hasDocumentationFor(PsiElement element, PsiElement originalElement) { - return getUrlFor(element, originalElement, false) != null; + return getOnlyUrlFor(element, originalElement) != null; } @Override