You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/06/30 21:53:12 UTC
(tomcat) branch main updated: Add utility URLConnection wrapper for review
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 13ecfa2f06 Add utility URLConnection wrapper for review
13ecfa2f06 is described below
commit 13ecfa2f066bd8d4e89f00d33d355f1598155551
Author: remm <re...@apache.org>
AuthorDate: Tue Jun 30 23:53:01 2026 +0200
Add utility URLConnection wrapper for review
Co authored using OpenCode.
---
.../tomcat/util/buf/CloseableURLConnection.java | 194 +++++++++++++++++++++
1 file changed, 194 insertions(+)
diff --git a/java/org/apache/tomcat/util/buf/CloseableURLConnection.java b/java/org/apache/tomcat/util/buf/CloseableURLConnection.java
new file mode 100644
index 0000000000..06e568ec8d
--- /dev/null
+++ b/java/org/apache/tomcat/util/buf/CloseableURLConnection.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.buf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.tomcat.util.ExceptionUtils;
+
+
+/**
+ * AutoCloseable wrapper for {@link URLConnection} that ensures all resources are released on close.
+ * <p>
+ * Different URLConnection subclasses require different cleanup:
+ * </p>
+ * <ul>
+ * <li>{@link HttpURLConnection} (including {@code HttpsURLConnection}) requires {@code disconnect()} to release the
+ * underlying socket.</li>
+ * <li>{@link JarURLConnection} requires the input stream to be closed to release the underlying
+ * {@code java.util.jar.JarFile}. When {@code setUseCaches(false)} is set, closing the input stream closes the
+ * {@code JarFile}, and calling {@code getInputStream()} again will throw {@link IllegalStateException}.</li>
+ * <li>Other URLConnection types only require any obtained streams to be closed.</li>
+ * </ul>
+ * <p>
+ * This wrapper sets {@code setUseCaches(false)} on the wrapped connection, tracks whether {@code getInputStream()} was
+ * called, and performs the appropriate cleanup in {@code close()}.
+ * </p>
+ */
+public final class CloseableURLConnection extends URLConnection implements AutoCloseable {
+
+
+ private final URLConnection connection;
+ private InputStream trackedStream;
+
+
+ /**
+ * Creates a new wrapper for the given URL by opening a connection.
+ * <p>
+ * {@code setUseCaches(false)} is called on the connection immediately.
+ * </p>
+ *
+ * @param url the URL to connect to
+ * @throws IOException if an I/O error occurs while opening the connection
+ */
+ public CloseableURLConnection(URL url) throws IOException {
+ this(url.openConnection());
+ }
+
+
+ /**
+ * Creates a new wrapper for the given URLConnection.
+ * <p>
+ * {@code setUseCaches(false)} is called on the connection immediately.
+ * </p>
+ *
+ * @param connection the URLConnection to wrap
+ */
+ public CloseableURLConnection(URLConnection connection) {
+ super(connection.getURL());
+ this.connection = connection;
+ connection.setUseCaches(false);
+ }
+
+
+ /**
+ * Returns the wrapped URLConnection.
+ *
+ * @return the wrapped URLConnection
+ */
+ public URLConnection getConnection() {
+ return connection;
+ }
+
+
+ @Override
+ public java.io.OutputStream getOutputStream() throws IOException {
+ return connection.getOutputStream();
+ }
+
+
+ @Override
+ public int getConnectTimeout() {
+ return connection.getConnectTimeout();
+ }
+
+
+ @Override
+ public void setConnectTimeout(int timeout) {
+ connection.setConnectTimeout(timeout);
+ }
+
+
+ @Override
+ public int getReadTimeout() {
+ return connection.getReadTimeout();
+ }
+
+
+ @Override
+ public void setReadTimeout(int timeout) {
+ connection.setReadTimeout(timeout);
+ }
+
+
+ @Override
+ public void connect() throws IOException {
+ connection.connect();
+ }
+
+
+ @Override
+ public void close() {
+ if (trackedStream != null) {
+ try {
+ trackedStream.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ } else if (connection instanceof JarURLConnection) {
+ try (InputStream is = connection.getInputStream()) {
+ // Open and immediately close to release the JarFile
+ } catch (Exception e) {
+ ExceptionUtils.handleThrowable(e);
+ }
+ }
+
+ if (connection instanceof HttpURLConnection) {
+ ((HttpURLConnection) connection).disconnect();
+ }
+ }
+
+
+ /**
+ * Returns the input stream for this URL connection. The stream is tracked and will be closed automatically when
+ * {@link #close()} is called.
+ *
+ * @return the input stream
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public InputStream getInputStream() throws IOException {
+ trackedStream = connection.getInputStream();
+ return trackedStream;
+ }
+
+
+ @Override
+ public String getContentType() {
+ return connection.getContentType();
+ }
+
+
+ @Override
+ public int getContentLength() {
+ return connection.getContentLength();
+ }
+
+
+ @Override
+ public long getContentLengthLong() {
+ return connection.getContentLengthLong();
+ }
+
+
+ @Override
+ public long getLastModified() {
+ return connection.getLastModified();
+ }
+
+
+ @Override
+ public String getHeaderField(String name) {
+ return connection.getHeaderField(name);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
Re: (tomcat) branch main updated: Add utility URLConnection wrapper for review
Posted by Mark Thomas <ma...@apache.org>.
On 30/06/2026 22:53, remm@apache.org wrote:
> This is an automated email from the ASF dual-hosted git repository.
>
> rmaucher pushed a commit to branch main
> in repository https://gitbox.apache.org/repos/asf/tomcat.git
>
>
> The following commit(s) were added to refs/heads/main by this push:
> new 13ecfa2f06 Add utility URLConnection wrapper for review
> 13ecfa2f06 is described below
>
> commit 13ecfa2f066bd8d4e89f00d33d355f1598155551
> Author: remm <re...@apache.org>
> AuthorDate: Tue Jun 30 23:53:01 2026 +0200
>
> Add utility URLConnection wrapper for review
>
> Co authored using OpenCode.
I looked at it and it looked OK to me for the places we have been
discussing using it.
Then I gave it to Claude and CoPilot to review.
They found quite a few other places were we could use this class. Given
that wider potential usage, the key finding was the new class extends
URLConnection but doesn't override all the methods pass the calls to the
wrapped connection. That might cause some bugs if we are not careful.
Proposed solutions:
a) don't extend URLConnection
b) override all the methods
Personally, I'm leaning towards b) as that way the class remains a
drop-in replacement for any current use of UrlConnection.
A less important issue is that if a stream can't be obtained (e.g. for
"jar:file:/some/path/my.jar!/" then the JarFile won't be closed.
Using getJarFile() rather than getInputStream() would fix that.
Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org