diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java index 229cf7a0e24e..5629398b47e1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java @@ -16,6 +16,7 @@ package com.intellij.ide.plugins; import com.intellij.openapi.extensions.PluginId; +import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.xml.sax.Attributes; @@ -24,9 +25,8 @@ import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; import java.util.List; -import java.util.Stack; -class RepositoryContentHandler extends DefaultHandler { +public class RepositoryContentHandler extends DefaultHandler { @NonNls public static final String CATEGORY = "category"; @NonNls public static final String IDEA_PLUGIN = "idea-plugin"; @NonNls public static final String NAME = "name"; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java index 1343553a4b7a..0a6262ca4eed 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,6 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URLConnection; import java.util.List; -import java.util.zip.GZIPInputStream; /** * @author stathik @@ -52,24 +51,6 @@ public class RepositoryHelper { return loadPluginsFromRepository(indicator, null); } - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - @NotNull - public static InputStream getConnectionInputStream(@NotNull URLConnection connection) throws IOException { - InputStream inputStream = connection.getInputStream(); - if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { - try { - return new GZIPInputStream(inputStream); - } - catch (IOException e) { - inputStream.close(); - throw e; - } - } - else { - return inputStream; - } - } - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public static List loadPluginsFromRepository(@Nullable final ProgressIndicator indicator, @Nullable BuildNumber buildnumber) throws Exception { final ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance(); @@ -83,6 +64,7 @@ public class RepositoryHelper { final File pluginListFile = new File(PathManager.getPluginsPath(), PLUGIN_LIST_FILE); if (pluginListFile.length() > 0) { try { + //noinspection SpellCheckingInspection url = url + "&crc32=" + Files.hash(pluginListFile, Hashing.crc32()).toString(); } catch (NoSuchMethodError e) { @@ -91,15 +73,12 @@ public class RepositoryHelper { } } - return HttpRequests.request(url).supportGzip(true).get(new ThrowableConvertor, Exception>() { + return HttpRequests.request(url).get(new ThrowableConvertor, Exception>() { @Override public List convert(URLConnection connection) throws Exception { - if (indicator != null) { - indicator.setText2(IdeBundle.message("progress.waiting.for.reply.from.plugin.manager", appInfo.getPluginManagerUrl())); - } - connection.connect(); if (indicator != null) { indicator.checkCanceled(); + indicator.setText2(IdeBundle.message("progress.waiting.for.reply.from.plugin.manager", appInfo.getPluginManagerUrl())); } if (connection instanceof HttpURLConnection && ((HttpURLConnection)connection).getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) { @@ -107,6 +86,7 @@ public class RepositoryHelper { } if (indicator != null) { + indicator.checkCanceled(); indicator.setText2(IdeBundle.message("progress.downloading.list.of.plugins")); } return readPluginsStream(connection, indicator, PLUGIN_LIST_FILE); @@ -114,11 +94,11 @@ public class RepositoryHelper { }); } - private synchronized static List readPluginsStream(@NotNull URLConnection connection, - @Nullable ProgressIndicator indicator, - @NotNull String file) throws Exception { + public synchronized static List readPluginsStream(@NotNull URLConnection connection, + @Nullable ProgressIndicator indicator, + @NotNull String file) throws Exception { File localFile; - InputStream input = getConnectionInputStream(connection); + InputStream input = HttpRequests.getInputStream(connection); try { localFile = createLocalPluginsDescriptions(file); OutputStream output = new FileOutputStream(localFile); @@ -159,10 +139,6 @@ public class RepositoryHelper { return temp; } - public static List loadPluginsFromDescription(@NotNull URLConnection connection, @Nullable ProgressIndicator indicator) throws Exception { - return readPluginsStream(connection, indicator, "host.xml"); - } - public static String getDownloadUrl() { return ApplicationInfoImpl.getShadowInstance().getPluginsDownloadUrl() + "?action=download&id="; } diff --git a/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java b/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java deleted file mode 100644 index 7bd9b76e8d81..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.ide.reporter; - -public class ConnectionException extends Exception { - - public ConnectionException(String message) { - super(message); - } - - public ConnectionException(Throwable cause) { - super(cause); - } - - public ConnectionException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index 3f72c3881164..fd6fce0474f6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -25,15 +25,15 @@ import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.BuildNumber; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.util.Consumer; import com.intellij.util.HttpRequests; import com.intellij.util.PathUtil; -import com.intellij.util.io.UrlConnectionUtil; +import com.intellij.util.ThrowableConvertor; import com.intellij.util.io.ZipUtil; import com.intellij.util.net.NetUtils; import org.jetbrains.annotations.NonNls; @@ -41,7 +41,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; -import java.net.HttpURLConnection; import java.net.URLConnection; import java.util.List; @@ -92,7 +91,7 @@ public class PluginDownloader { return prepareToInstall(progressIndicator, myBuildNumber); } - public boolean prepareToInstall(@Nullable ProgressIndicator progressIndicator, @Nullable BuildNumber forBuildNumber) throws IOException { + public boolean prepareToInstall(@NotNull ProgressIndicator progressIndicator, @Nullable BuildNumber forBuildNumber) throws IOException { if (myFile != null) { return true; } @@ -226,65 +225,54 @@ public class PluginDownloader { } } - private File downloadPlugin(@Nullable final ProgressIndicator progressIndicator) throws IOException { - final File pluginsTemp = new File(PathManager.getPluginTempPath()); + @NotNull + private File downloadPlugin(@NotNull final ProgressIndicator progressIndicator) throws IOException { + File pluginsTemp = new File(PathManager.getPluginTempPath()); if (!pluginsTemp.exists() && !pluginsTemp.mkdirs()) { throw new IOException(IdeBundle.message("error.cannot.create.temp.dir", pluginsTemp)); } final File file = FileUtil.createTempFile(pluginsTemp, "plugin_", "_download", true, false); - if (progressIndicator != null) { - progressIndicator.setText(IdeBundle.message("progress.connecting")); - } + progressIndicator.checkCanceled(); + progressIndicator.setText(IdeBundle.message("progress.downloading.plugin", getPluginName())); - URLConnection connection = null; - try { - Pair result = HttpRequests.openConnection(myPluginUrl, false); - if (result.second != null) { - myPluginUrl = result.second; + return HttpRequests.request(myPluginUrl).supportGzip(false).effectiveUrlConsumer(new Consumer() { + @Override + public void consume(String url) { + myPluginUrl = url; } - connection = result.first; + }).get(new ThrowableConvertor() { + @Override + public File convert(URLConnection connection) throws IOException { + progressIndicator.checkCanceled(); - final InputStream is = (ApplicationManager.getApplication() != null) - ? UrlConnectionUtil.getConnectionInputStream(connection, progressIndicator) - : connection.getInputStream(); - if (is == null) { - throw new IOException("Failed to open connection"); - } - - if (progressIndicator != null && ApplicationManager.getApplication() != null) { - progressIndicator.setText(IdeBundle.message("progress.downloading.plugin", getPluginName())); - } - try { - final OutputStream fos = new BufferedOutputStream(new FileOutputStream(file, false)); + InputStream input = HttpRequests.getInputStream(connection); try { - NetUtils.copyStreamContent(progressIndicator, is, fos, connection.getContentLength()); + OutputStream fileOut = new FileOutputStream(file); + try { + NetUtils.copyStreamContent(progressIndicator, input, fileOut, connection.getContentLength()); + } + finally { + fileOut.close(); + } } finally { - fos.close(); + input.close(); } - } - finally { - is.close(); - } - if (myFileName == null) { - myFileName = guessFileName(connection, file); - } + if (myFileName == null) { + myFileName = guessFileName(connection, file); + } - final File newFile = new File(file.getParentFile(), myFileName); - FileUtil.rename(file, newFile); - return newFile; - } - finally { - if (connection instanceof HttpURLConnection) { - ((HttpURLConnection)connection).disconnect(); + File newFile = new File(file.getParentFile(), myFileName); + FileUtil.rename(file, newFile); + return newFile; } - } + }); } @NotNull - private String guessFileName(final URLConnection connection, final File file) throws IOException { + private String guessFileName(@NotNull URLConnection connection, @NotNull File file) throws IOException { String fileName = null; final String contentDisposition = connection.getHeaderField("Content-Disposition"); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index eb1a454735c1..e7a069a653e3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.diagnostic.IdeErrorsDialog; import com.intellij.ide.IdeBundle; import com.intellij.ide.plugins.*; -import com.intellij.ide.reporter.ConnectionException; import com.intellij.ide.util.PropertiesComponent; import com.intellij.notification.*; import com.intellij.openapi.application.ApplicationInfo; @@ -30,24 +29,20 @@ import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.diagnostic.IdeaLoggingEvent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; +import com.intellij.openapi.progress.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Function; -import com.intellij.util.HttpRequests; -import com.intellij.util.PlatformUtils; -import com.intellij.util.ThrowableConvertor; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.UrlConnectionUtil; import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.net.NetUtils; import com.intellij.util.ui.UIUtil; import org.jdom.Document; import org.jdom.Element; @@ -58,15 +53,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.*; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * See XML file by {@link com.intellij.openapi.application.ex.ApplicationInfoEx#getUpdateUrls()} for reference. @@ -133,7 +127,6 @@ public final class UpdateChecker { ProgressManager.getInstance().run(new Task.Backgroundable(project, IdeBundle.message("updates.checking.progress"), true) { @Override public void run(@NotNull ProgressIndicator indicator) { - indicator.setIndeterminate(true); doUpdateAndShowResult(project, !fromSettings, true, settings, indicator, null); } @@ -163,7 +156,9 @@ public final class UpdateChecker { settings.setKnownChannelIds(result.getAllChannelsIds()); } else if (result.getState() == UpdateStrategy.State.CONNECTION_ERROR) { - showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed")); + //noinspection ThrowableResultOfMethodCallIgnored + showErrorMessage(manualCheck, + result.getError() instanceof InterruptedIOException ? IdeBundle.message("updates.timeout.error") : IdeBundle.message("updates.error.connection.failed")); return; } @@ -287,7 +282,7 @@ public final class UpdateChecker { if (isReadyToUpdate(pluginId, pluginVersion)) { descriptor = downloader.getDescriptor(); if (descriptor == null) { - if (downloader.prepareToInstall(indicator, buildNumber)) { + if (downloader.prepareToInstall(indicator == null ? new EmptyProgressIndicator() : indicator, buildNumber)) { descriptor = downloader.getDescriptor(); } ourUpdatedPlugins.put(pluginId, downloader); @@ -351,45 +346,74 @@ public final class UpdateChecker { return checkPluginsHost(host, downloaded, null, collectToUpdate, indicator, null); } - private static boolean checkPluginsHost(String host, + private static boolean checkPluginsHost(@NotNull String host, final Map downloaded, final @Nullable Collection incompatiblePlugins, - final boolean collectToUpdate, - @Nullable ProgressIndicator indicator, + boolean collectToUpdate, + @Nullable final ProgressIndicator indicator, final BuildNumber buildNumber) throws Exception { + String url; + if (StandardFileSystems.FILE_PROTOCOL.equals(new URL(host).getProtocol())) { + url = host; + } + else { + url = host + (host.contains("?") ? '&' : '?') + "build=" + ApplicationInfo.getInstance().getBuild().asString(); + } + + BufferExposingByteArrayOutputStream bytes = HttpRequests.request(url) + .get(new ThrowableConvertor() { + @Override + public BufferExposingByteArrayOutputStream convert(URLConnection connection) throws Exception { + InputStream input = HttpRequests.getInputStream(connection); + try { + BufferExposingByteArrayOutputStream output = new BufferExposingByteArrayOutputStream(); + try { + NetUtils.copyStreamContent(indicator, input, output, connection.getContentLength()); + } + finally { + output.close(); + } + return output; + } + finally { + input.close(); + } + } + }); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes.getInternalBuffer(), 0, bytes.size()); final Document document; try { - document = JDOMUtil.loadDocument(RepositoryHelper.getConnectionInputStream(loadVersionInfo(host))); + document = JDOMUtil.loadDocument(inputStream); } catch (JDOMException e) { return false; } + finally { + inputStream.reset(); + } - final List descriptors = RepositoryHelper.loadPluginsFromDescription(loadVersionInfo(host), indicator); - for (IdeaPluginDescriptor descriptor : descriptors) { + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + RepositoryContentHandler handler = new RepositoryContentHandler(); + parser.parse(inputStream, handler); + + for (IdeaPluginDescriptor descriptor : handler.getPluginsList()) { ((PluginNode)descriptor).setRepositoryName(host); prepareToInstall(PluginDownloader.createDownloader(descriptor, buildNumber), buildNumber, downloaded, incompatiblePlugins, collectToUpdate, indicator); } boolean success = true; - for (Object plugin : document.getRootElement().getChildren("plugin")) { - final Element pluginElement = (Element)plugin; + for (Element pluginElement : document.getRootElement().getChildren("plugin")) { final String pluginId = pluginElement.getAttributeValue("id"); - final String pluginUrl = pluginElement.getAttributeValue("url"); + String pluginUrl = pluginElement.getAttributeValue("url"); final String pluginVersion = pluginElement.getAttributeValue("version"); - final Element descriptionElement = pluginElement.getChild("description"); - final String description; - if (descriptionElement != null) { - description = descriptionElement.getText(); - } else { - description = null; - } + Element descriptionElement = pluginElement.getChild("description"); + String description = descriptionElement != null ? descriptionElement.getText() : null; - final List dependsPlugins = new ArrayList(); - final List depends = pluginElement.getChildren("depends"); - for (Object depend : depends) { - dependsPlugins.add(PluginId.getId(((Element)depend).getText())); + List dependsPlugins = new SmartList(); + for (Element depend : pluginElement.getChildren("depends")) { + dependsPlugins.add(PluginId.getId(depend.getText())); } if (pluginId == null) { @@ -404,8 +428,10 @@ public final class UpdateChecker { continue; } - final VirtualFile pluginFile = PluginDownloader.findPluginFile(pluginUrl, host); - if (pluginFile == null) continue; + VirtualFile pluginFile = PluginDownloader.findPluginFile(pluginUrl, host); + if (pluginFile == null) { + continue; + } if (collectToUpdate) { final String finalPluginUrl = getPluginUrl(pluginFile); @@ -436,7 +462,8 @@ public final class UpdateChecker { String pluginVersion, BuildNumber buildNumber, Map downloaded, - Collection incompatiblePlugins, boolean collectToUpdate, ProgressIndicator indicator) { + Collection incompatiblePlugins, boolean collectToUpdate, + ProgressIndicator indicator) { try { if (indicator != null) { indicator.setText2(finalPluginUrl); @@ -463,7 +490,7 @@ public final class UpdateChecker { } @Nullable - private static UpdatesInfo loadUpdatesInfo(@Nullable final String updateUrl) throws Exception { + private static UpdatesInfo loadUpdatesInfo(@Nullable String updateUrl) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("load update xml (UPDATE_URL='" + updateUrl + "' )"); } @@ -477,7 +504,7 @@ public final class UpdateChecker { .get(new ThrowableConvertor() { @Override public UpdatesInfo convert(URLConnection connection) throws Exception { - InputStream inputStream = connection.getInputStream(); + InputStream inputStream = HttpRequests.getInputStream(connection); try { return new UpdatesInfo(JDOMUtil.loadDocument(inputStream).getRootElement()); } @@ -502,9 +529,6 @@ public final class UpdateChecker { return new CheckForUpdateResult(UpdateStrategy.State.NOTHING_LOADED); } } - catch (InterruptedIOException e) { - return new CheckForUpdateResult(UpdateStrategy.State.CONNECTION_ERROR, new ConnectionException(IdeBundle.message("updates.timeout.error"))); - } catch (Exception e) { return new CheckForUpdateResult(UpdateStrategy.State.CONNECTION_ERROR, e); } @@ -645,49 +669,6 @@ public final class UpdateChecker { } } - @NotNull - private static URLConnection loadVersionInfo(@NotNull final String url) throws Exception { - final Ref connectionRef = Ref.create(); - final Ref exception = Ref.create(); - Future downloadThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - try { - String urlToCheck; - if (!StandardFileSystems.FILE_PROTOCOL.equals(new URL(url).getProtocol())) { - urlToCheck = url + (url.contains("?") ? "&" : "?") + "build=" + ApplicationInfo.getInstance().getBuild().asString(); - } - else { - urlToCheck = url; - } - - URLConnection connection = HttpRequests.openConnection(urlToCheck, true).first; - connection.connect(); - connectionRef.set(connection); - } - catch (IOException e) { - exception.set(e); - } - } - }); - - try { - downloadThreadFuture.get(5, TimeUnit.SECONDS); - } - catch (TimeoutException ignored) { - } - - if (!downloadThreadFuture.isDone()) { - downloadThreadFuture.cancel(true); - throw new ConnectionException(IdeBundle.message("updates.timeout.error")); - } - - if (!exception.isNull()) { - throw exception.get(); - } - return connectionRef.get(); - } - public static String getInstallationUID(final PropertiesComponent propertiesComponent) { if (SystemInfo.isWindows) { String uid = getInstallationUIDOnWindows(propertiesComponent); diff --git a/platform/platform-impl/src/com/intellij/util/HttpRequests.java b/platform/platform-impl/src/com/intellij/util/HttpRequests.java index 38cf8682a8fb..9bc99d1d5208 100644 --- a/platform/platform-impl/src/com/intellij/util/HttpRequests.java +++ b/platform/platform-impl/src/com/intellij/util/HttpRequests.java @@ -17,25 +17,29 @@ package com.intellij.util; import com.intellij.ide.IdeBundle; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.ClassLoaderUtil; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.ThrowableComputable; import com.intellij.util.net.HttpConfigurable; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; +import java.util.zip.GZIPInputStream; +/** + * GZip supported by default, so, you must use {@link #getInputStream(java.net.URLConnection)} to get connection input stream. + */ public final class HttpRequests { public static class HttpRequestBuilder { private final String url; private int connectTimeout = HttpConfigurable.CONNECTION_TIMEOUT; private int readTimeout = HttpConfigurable.CONNECTION_TIMEOUT; - private boolean supportGzip; + private Consumer effectiveUrlConsumer; + + private boolean supportGzip = true; private HttpRequestBuilder(@NotNull String url) { this.url = url; @@ -47,6 +51,7 @@ public final class HttpRequests { return this; } + @SuppressWarnings("unused") @NotNull public HttpRequestBuilder readTimeout(int value) { readTimeout = value; @@ -59,7 +64,13 @@ public final class HttpRequests { return this; } - public T get(@NotNull final ThrowableConvertor handler) throws Exception { + @NotNull + public HttpRequestBuilder effectiveUrlConsumer(Consumer value) { + effectiveUrlConsumer = value; + return this; + } + + public T get(@NotNull final ThrowableConvertor handler) throws E, IOException { return loadData(this, handler); } } @@ -69,30 +80,46 @@ public final class HttpRequests { return new HttpRequestBuilder(url); } - private static T loadData(@NotNull final HttpRequestBuilder requestBuilder, @NotNull final ThrowableConvertor handler) throws Exception { - return ClassLoaderUtil.runWithClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()), new ThrowableComputable() { - @Override - public T compute() throws Exception { - URLConnection connection = openConnection(requestBuilder.url, requestBuilder.supportGzip).first; - try { - return handler.convert(connection); - } - finally { - if (connection instanceof HttpURLConnection) { - ((HttpURLConnection)connection).disconnect(); - } + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + @NotNull + public static InputStream getInputStream(@NotNull URLConnection connection) throws IOException { + InputStream inputStream = connection.getInputStream(); + if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { + try { + return new GZIPInputStream(inputStream); + } + catch (IOException e) { + inputStream.close(); + throw e; + } + } + else { + return inputStream; + } + } + + private static T loadData(@NotNull HttpRequestBuilder requestBuilder, @NotNull ThrowableConvertor handler) + throws E, IOException { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0], oldClassLoader)); + try { + URLConnection connection = openConnection(requestBuilder); + try { + return handler.convert(connection); + } + finally { + if (connection instanceof HttpURLConnection) { + ((HttpURLConnection)connection).disconnect(); } } - }); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } } @NotNull - public static Pair openConnection(@NotNull String initialUrl, boolean supportGzip) throws IOException { - return openConnection(request(initialUrl).supportGzip(supportGzip)); - } - - @NotNull - private static Pair openConnection(@NotNull HttpRequestBuilder requestBuilder) throws IOException { + private static URLConnection openConnection(@NotNull HttpRequestBuilder requestBuilder) throws IOException { int i = 0; String url = requestBuilder.url; while (i++ < 99) { @@ -132,7 +159,11 @@ public final class HttpRequests { } } } - return Pair.create(connection, url == requestBuilder.url ? null : url); + + if (url != requestBuilder.url && requestBuilder.effectiveUrlConsumer != null) { + requestBuilder.effectiveUrlConsumer.consume(url); + } + return connection; } throw new IOException("Infinite redirection"); } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index e0561fb7c788..0eb3fbde6b09 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -531,7 +531,6 @@ button.http.proxy.settings=&HTTP Proxy Settings... group.vendor=Vendor plugin.status.installed=Installed progress.waiting.for.reply.from.plugin.manager=Waiting for reply from {0} -progress.connecting=Connecting... progress.downloading.plugin=Downloading plugin ''{0}'' error.cannot.create.temp.dir=Unable to create temp directory ''{0}'' error.connection.failed.with.http.code.N=Connection failed with HTTP code {0}